1mod attrs;
34mod lower;
35mod pretty;
36#[cfg(test)]
37mod tests;
38
39use std::{
40 fmt::{self, Debug},
41 hash::Hash,
42 ops::Index,
43 sync::OnceLock,
44};
45
46use ast::{AstNode, StructKind};
47use base_db::{Crate, SourceDatabase};
48use cfg::CfgOptions;
49use either::Either;
50use hir_expand::{
51 ExpandTo, HirFileId,
52 mod_path::{ModPath, PathKind},
53 name::Name,
54};
55use intern::Interned;
56use la_arena::{Idx, RawIdx};
57use span::{
58 AstIdNode, Edition, FileAstId, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, Span, SpanAnchor,
59 SyntaxContext,
60};
61use stdx::never;
62use syntax::{SourceFile, SyntaxKind, ast, match_ast};
63use thin_vec::ThinVec;
64use tt::TextRange;
65
66use crate::{BlockId, attrs::parse_extra_crate_attrs};
67
68pub(crate) use crate::item_tree::{
69 attrs::*,
70 lower::{lower_use_tree, visibility_from_ast},
71};
72
73#[derive(Copy, Clone, Eq, PartialEq)]
74pub(crate) struct RawVisibilityId(u32);
75
76impl RawVisibilityId {
77 const PUB: Self = RawVisibilityId(u32::MAX);
78 const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
79 const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
80 const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
81}
82
83impl fmt::Debug for RawVisibilityId {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 let mut f = f.debug_tuple("RawVisibilityId");
86 match *self {
87 Self::PUB => f.field(&"pub"),
88 Self::PRIV_IMPLICIT | Self::PRIV_EXPLICIT => f.field(&"pub(self)"),
89 Self::PUB_CRATE => f.field(&"pub(crate)"),
90 _ => f.field(&self.0),
91 };
92 f.finish()
93 }
94}
95
96fn lower_extra_crate_attrs<'a>(
97 db: &dyn SourceDatabase,
98 crate_attrs_as_src: SourceFile,
99 file_id: span::EditionedFileId,
100 cfg_options: &dyn Fn() -> &'a CfgOptions,
101) -> AttrsOrCfg {
102 #[derive(Copy, Clone)]
103 struct FakeSpanMap {
104 file_id: span::EditionedFileId,
105 }
106 impl syntax_bridge::SpanMapper for FakeSpanMap {
107 fn span_for(&self, range: TextRange) -> Span {
108 Span {
109 range,
110 anchor: SpanAnchor {
111 file_id: self.file_id,
112 ast_id: NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER,
113 },
114 ctx: SyntaxContext::root(self.file_id.edition()),
115 }
116 }
117 }
118
119 let span_map = FakeSpanMap { file_id };
120 AttrsOrCfg::lower(db, &crate_attrs_as_src, cfg_options, span_map)
121}
122
123pub fn file_item_tree(db: &dyn SourceDatabase, file_id: HirFileId, krate: Crate) -> &ItemTree {
125 match file_item_tree_query(db, file_id, krate) {
126 Some(item_tree) => item_tree,
127 None => {
128 static EMPTY: OnceLock<ItemTree> = OnceLock::new();
129 EMPTY.get_or_init(|| ItemTree {
130 top_level: Box::new([]),
131 attrs: ThinVec::new(),
132 small_data: ThinVec::new(),
133 big_data: ThinVec::new(),
134 vis: ItemVisibilities { arena: ThinVec::new() },
135 })
136 }
137 }
138}
139
140#[salsa::tracked(returns(ref))]
141fn file_item_tree_query(
142 db: &dyn SourceDatabase,
143 file_id: HirFileId,
144 krate: Crate,
145) -> Option<Box<ItemTree>> {
146 let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
147
148 let mut ctx = lower::Ctx::new(db, file_id, krate);
149 let syntax = file_id.parse_or_expand(db);
150 let mut item_tree = match_ast! {
151 match syntax {
152 ast::SourceFile(file) => {
153 let root_file_id = krate.root_file_id(db);
154 let extra_top_attrs = (file_id == root_file_id).then(|| {
155 parse_extra_crate_attrs(db, krate).map(|crate_attrs| {
156 lower_extra_crate_attrs(db, crate_attrs, root_file_id.span_file_id(db), &|| ctx.cfg_options())
157 })
158 }).flatten();
159 let top_attrs = match extra_top_attrs {
160 Some(attrs @ AttrsOrCfg::Enabled { .. }) => attrs.merge(ctx.lower_attrs(&file)),
161 Some(attrs @ AttrsOrCfg::CfgDisabled(_)) => attrs,
162 None => ctx.lower_attrs(&file)
163 };
164 ctx.add_attrs(ModItemId::TOP_OWNER, top_attrs);
165 ctx.lower_module_items(&file)
166 },
167 ast::MacroItems(items) => {
168 ctx.lower_module_items(&items)
169 },
170 ast::MacroStmts(stmts) => {
171 ctx.lower_macro_stmts(stmts)
174 },
175 _ => {
176 if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
177 return Default::default();
178 }
179 panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
180 },
181 }
182 };
183 if item_tree.is_empty() {
184 None
185 } else {
186 item_tree.finalize();
187 Some(Box::new(item_tree))
188 }
189}
190
191#[salsa::tracked(returns(ref))]
192pub(crate) fn block_item_tree_query(
193 db: &dyn SourceDatabase,
194 block: BlockId,
195 krate: Crate,
196) -> ItemTree {
197 let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
198 let ast_id = block.ast_id(db);
199 let block = ast_id.to_node(db);
200
201 let ctx = lower::Ctx::new(db, ast_id.file_id, krate);
202 let mut item_tree = ctx.lower_block(&block);
203 item_tree.finalize();
204 item_tree
205}
206
207#[derive(Debug, Default, Eq, PartialEq)]
209pub struct ItemTree {
210 top_level: Box<[ModItemId]>,
211 attrs: ThinVec<(ModItemId, AttrsOrCfg)>,
213 vis: ItemVisibilities,
214 big_data: ThinVec<(FileAstId<ast::Item>, BigModItem)>,
215 small_data: ThinVec<(FileAstId<ast::Item>, SmallModItem)>,
216}
217
218impl ItemTree {
219 pub(crate) fn top_level_items(&self) -> &[ModItemId] {
222 &self.top_level
223 }
224
225 #[inline]
227 pub(crate) fn top_level_attrs(&self) -> Option<&AttrsOrCfg> {
228 self.attrs.last().filter(|(id, _)| *id == ModItemId::TOP_OWNER).map(|(_, attrs)| attrs)
229 }
230
231 #[inline]
232 pub(crate) fn attrs(&self, of: ModItemId) -> Option<&AttrsOrCfg> {
233 self.attrs.binary_search_by_key(&of, |(id, _)| *id).ok().map(|index| &self.attrs[index].1)
234 }
235
236 pub fn item_tree_stats(&self) -> ItemTreeDataStats {
240 let mut traits = 0;
241 let mut impls = 0;
242 let mut mods = 0;
243 let mut macro_calls = 0;
244 let mut macro_rules = 0;
245 for (_, item) in &self.small_data {
246 match item {
247 SmallModItem::Trait(_) => traits += 1,
248 SmallModItem::Impl(_) => impls += 1,
249 SmallModItem::MacroRules(_) => macro_rules += 1,
250 SmallModItem::MacroCall(_) => macro_calls += 1,
251 _ => {}
252 }
253 }
254 for (_, item) in &self.big_data {
255 match item {
256 BigModItem::Mod(_) => mods += 1,
257 _ => {}
258 }
259 }
260 ItemTreeDataStats { traits, impls, mods, macro_calls, macro_rules }
261 }
262
263 pub fn pretty_print(&self, db: &dyn SourceDatabase, edition: Edition) -> String {
264 pretty::print_item_tree(db, self, edition)
265 }
266
267 fn is_empty(&self) -> bool {
268 let ItemTree { top_level, attrs, vis: _, big_data: _, small_data: _ } = self;
269 top_level.is_empty() && attrs.is_empty()
272 }
273
274 fn finalize(&mut self) {
275 self.attrs.sort_unstable_by_key(|(id, _)| *id);
276
277 let ItemTree { top_level: _, attrs, big_data, small_data, vis } = self;
278 attrs.shrink_to_fit();
279 big_data.shrink_to_fit();
280 small_data.shrink_to_fit();
281 vis.arena.shrink_to_fit();
282 }
283}
284
285#[derive(Default, Debug, Eq, PartialEq)]
286struct ItemVisibilities {
287 arena: ThinVec<RawVisibility>,
288}
289
290#[derive(Debug, Clone, Eq, PartialEq)]
291enum SmallModItem {
292 Const(Const),
293 Enum(Enum),
294 ExternBlock(ExternBlock),
295 Function(Function),
296 Impl(Impl),
297 Macro2(Macro2),
298 MacroCall(MacroCall),
299 MacroRules(MacroRules),
300 Static(Static),
301 Trait(Trait),
302 TypeAlias(TypeAlias),
303 Union(Union),
304}
305
306#[derive(Debug, Clone, Eq, PartialEq)]
307enum BigModItem {
308 ExternCrate(ExternCrate),
309 Mod(Mod),
310 Use(Use),
311 Struct(Struct),
312}
313
314#[cfg(target_pointer_width = "64")]
318const _: [(); std::mem::size_of::<BigModItem>()] = [(); std::mem::size_of::<[usize; 5]>()];
319#[cfg(target_pointer_width = "64")]
320const _: [(); std::mem::size_of::<SmallModItem>()] = [(); std::mem::size_of::<[usize; 3]>()];
321
322#[derive(Default, Debug, Eq, PartialEq)]
323pub struct ItemTreeDataStats {
324 pub traits: usize,
325 pub impls: usize,
326 pub mods: usize,
327 pub macro_calls: usize,
328 pub macro_rules: usize,
329}
330
331pub(crate) trait ItemTreeNode: Clone {
333 type Source: AstIdNode;
334}
335
336#[allow(type_alias_bounds)]
337pub(crate) type ItemTreeAstId<T: ItemTreeNode> = FileAstId<T::Source>;
338
339#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
341pub struct TreeId {
342 file: HirFileId,
343 block: Option<BlockId>,
344}
345
346impl TreeId {
347 pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
348 Self { file, block }
349 }
350
351 pub(crate) fn item_tree<'db>(
352 &self,
353 db: &'db dyn SourceDatabase,
354 krate: Crate,
355 ) -> &'db ItemTree {
356 match self.block {
357 Some(block) => block_item_tree_query(db, block, krate),
358 None => file_item_tree(db, self.file, krate),
359 }
360 }
361
362 #[inline]
363 pub fn file_id(self) -> HirFileId {
364 self.file
365 }
366
367 pub(crate) fn is_block(self) -> bool {
368 self.block.is_some()
369 }
370}
371
372#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
373pub struct ModItemId {
374 index: u32,
376}
377
378impl ModItemId {
379 const TOP_OWNER: ModItemId = ModItemId { index: u32::MAX };
380
381 #[inline]
382 fn new_small(index: u32) -> Self {
383 debug_assert!(
384 (index & 0x80_00_00_00) == 0 && index != (ModItemId::TOP_OWNER.index >> 1),
385 "too big index"
386 );
387 Self { index: index << 1 }
388 }
389 #[inline]
390 fn new_big(index: u32) -> Self {
391 debug_assert!(
392 (index & 0x80_00_00_00) == 0 && index != (ModItemId::TOP_OWNER.index >> 1),
393 "too big index"
394 );
395 Self { index: (index << 1) | 0b1 }
396 }
397
398 #[inline]
399 fn get(
400 self,
401 item_tree: &ItemTree,
402 ) -> (FileAstId<ast::Item>, Either<&SmallModItem, &BigModItem>) {
403 let index = self.index >> 1;
404 match self.index & 0b1 {
405 0 => {
406 let (ast_id, data) = &item_tree.small_data[index as usize];
407 (*ast_id, Either::Left(data))
408 }
409 1 => {
410 let (ast_id, data) = &item_tree.big_data[index as usize];
411 (*ast_id, Either::Right(data))
412 }
413 _ => unreachable!(),
414 }
415 }
416
417 #[inline]
418 pub(crate) fn ast_id(self, item_tree: &ItemTree) -> FileAstId<ast::Item> {
419 self.get(item_tree).0
420 }
421}
422
423macro_rules! mod_items {
424 ($mod_item:ident -> $( $typ:ident by $either:ident -> $ast:ty ),+ $(,)? ) => {
425 #[derive(Debug, Copy, Clone)]
426 pub(crate) enum $mod_item<'a> {
427 $(
428 $typ(FileAstId<$ast>, &'a $typ),
429 )+
430 }
431
432 impl ItemTree {
433 #[inline]
434 pub(crate) fn index(&self, id: ModItemId) -> $mod_item<'_> {
435 use BigModItem::*;
436 use SmallModItem::*;
437
438 let (ast_id, item) = id.get(self);
439 match item {
440 $( Either::$either($typ(item)) => $mod_item::$typ(ast_id.downcast_unchecked(), item), )+
441 }
442 }
443 }
444
445 $(
446 impl ItemTreeNode for $typ {
447 type Source = $ast;
448 }
449 )+
450 };
451}
452
453mod_items! {
454ModItemKind ->
455 Const by Left -> ast::Const,
456 Enum by Left -> ast::Enum,
457 ExternBlock by Left -> ast::ExternBlock,
458 ExternCrate by Right -> ast::ExternCrate,
459 Function by Left -> ast::Fn,
460 Impl by Left -> ast::Impl,
461 Macro2 by Left -> ast::MacroDef,
462 MacroCall by Left -> ast::MacroCall,
463 MacroRules by Left -> ast::MacroRules,
464 Mod by Right -> ast::Module,
465 Static by Left -> ast::Static,
466 Struct by Right -> ast::Struct,
467 Trait by Left -> ast::Trait,
468 TypeAlias by Left -> ast::TypeAlias,
469 Union by Left -> ast::Union,
470 Use by Right -> ast::Use,
471}
472
473impl Index<RawVisibilityId> for ItemTree {
474 type Output = RawVisibility;
475 fn index(&self, index: RawVisibilityId) -> &Self::Output {
476 static VIS_PUB: RawVisibility = RawVisibility::Public;
477 static VIS_PRIV_IMPLICIT: RawVisibility =
478 RawVisibility::PubSelf(VisibilityExplicitness::Implicit);
479 static VIS_PRIV_EXPLICIT: RawVisibility =
480 RawVisibility::PubSelf(VisibilityExplicitness::Explicit);
481 static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate;
482
483 match index {
484 RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
485 RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
486 RawVisibilityId::PUB => &VIS_PUB,
487 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
488 _ => &self.vis.arena[index.0 as usize],
489 }
490 }
491}
492
493#[derive(Debug, Clone, Eq, PartialEq)]
494pub struct Use {
495 pub(crate) visibility: RawVisibilityId,
496 pub(crate) use_tree: UseTree,
497}
498
499#[derive(Debug, Clone, Eq, PartialEq)]
500pub struct UseTree {
501 kind: UseTreeKind,
502}
503
504#[derive(Debug, Clone, PartialEq, Eq)]
507pub enum ImportAlias {
508 Underscore,
510 Alias(Name),
512}
513
514impl ImportAlias {
515 pub fn display(&self, edition: Edition) -> impl fmt::Display + '_ {
516 ImportAliasDisplay { value: self, edition }
517 }
518}
519
520struct ImportAliasDisplay<'a> {
521 value: &'a ImportAlias,
522 edition: Edition,
523}
524
525impl fmt::Display for ImportAliasDisplay<'_> {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 match self.value {
528 ImportAlias::Underscore => f.write_str("_"),
529 ImportAlias::Alias(name) => fmt::Display::fmt(&name.display_no_db(self.edition), f),
530 }
531 }
532}
533
534#[derive(Debug, Clone, Eq, PartialEq)]
535pub enum UseTreeKind {
536 Single { path: Interned<ModPath>, alias: Option<ImportAlias> },
542
543 Glob { path: Option<Interned<ModPath>> },
548
549 Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> },
553}
554
555#[derive(Debug, Clone, Eq, PartialEq)]
556pub struct ExternCrate {
557 pub name: Name,
558 pub alias: Option<ImportAlias>,
559 pub(crate) visibility: RawVisibilityId,
560}
561
562#[derive(Debug, Clone, Eq, PartialEq)]
563pub struct ExternBlock {
564 pub(crate) children: Box<[ModItemId]>,
565}
566
567#[derive(Debug, Clone, Eq, PartialEq)]
568pub struct Function {
569 pub name: Name,
570 pub(crate) visibility: RawVisibilityId,
571}
572
573#[derive(Debug, Clone, Eq, PartialEq)]
574pub struct Struct {
575 pub name: Name,
576 pub(crate) visibility: RawVisibilityId,
577 pub(crate) value_ns_ctor: StructValueNsCtor,
578}
579
580#[derive(Debug, Clone, PartialEq, Eq)]
581pub(crate) enum StructValueNsCtor {
582 NoValueNsCtor,
583 ValueNsCtorWithVis(RawVisibilityId),
584 ValueNsCtorWithMinVis(ThinVec<RawVisibilityId>),
585}
586
587#[derive(Debug, Clone, Eq, PartialEq)]
588pub struct Union {
589 pub name: Name,
590 pub(crate) visibility: RawVisibilityId,
591}
592
593#[derive(Debug, Clone, Eq, PartialEq)]
594pub struct Enum {
595 pub name: Name,
596 pub(crate) visibility: RawVisibilityId,
597}
598
599#[derive(Debug, Copy, Clone, PartialEq, Eq)]
600pub enum FieldsShape {
601 Record,
602 Tuple,
603 Unit,
604}
605
606impl FieldsShape {
607 #[inline]
608 pub fn has_value_ns_ctor(self) -> bool {
609 match self {
610 FieldsShape::Record => false,
611 FieldsShape::Tuple | FieldsShape::Unit => true,
612 }
613 }
614}
615
616#[derive(Debug, Clone, PartialEq, Eq, Hash)]
618pub enum RawVisibility {
619 Module(Interned<ModPath>, VisibilityExplicitness),
622 PubSelf(VisibilityExplicitness),
624 PubCrate,
626 Public,
628}
629
630#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
633pub enum VisibilityExplicitness {
634 Explicit,
635 Implicit,
636}
637
638impl VisibilityExplicitness {
639 pub fn is_explicit(&self) -> bool {
640 matches!(self, Self::Explicit)
641 }
642}
643
644#[derive(Debug, Clone, Eq, PartialEq)]
645pub struct Const {
646 pub name: Option<Name>,
648 pub(crate) visibility: RawVisibilityId,
649}
650
651#[derive(Debug, Clone, Eq, PartialEq)]
652pub struct Static {
653 pub name: Name,
654 pub(crate) visibility: RawVisibilityId,
655}
656
657#[derive(Debug, Clone, Eq, PartialEq)]
658pub struct Trait {
659 pub name: Name,
660 pub(crate) visibility: RawVisibilityId,
661}
662
663#[derive(Debug, Clone, Eq, PartialEq)]
664pub struct Impl {
665 pub is_trait_impl: bool,
666}
667
668#[derive(Debug, Clone, PartialEq, Eq)]
669pub struct TypeAlias {
670 pub name: Name,
671 pub(crate) visibility: RawVisibilityId,
672}
673
674#[derive(Debug, Clone, Eq, PartialEq)]
675pub struct Mod {
676 pub name: Name,
677 pub(crate) visibility: RawVisibilityId,
678 pub(crate) kind: ModKind,
679}
680
681#[derive(Debug, Clone, Eq, PartialEq)]
682pub(crate) enum ModKind {
683 Inline { items: Box<[ModItemId]> },
685 Outline,
687}
688
689#[derive(Debug, Clone, Eq, PartialEq)]
690pub struct MacroCall {
691 pub path: Interned<ModPath>,
693 pub expand_to: ExpandTo,
694 pub ctxt: SyntaxContext,
695}
696
697#[derive(Debug, Clone, Eq, PartialEq)]
698pub struct MacroRules {
699 pub name: Name,
701}
702
703#[derive(Debug, Clone, Eq, PartialEq)]
705pub struct Macro2 {
706 pub name: Name,
707 pub(crate) visibility: RawVisibilityId,
708}
709
710#[derive(Clone, Copy, Debug, Eq, PartialEq)]
711pub enum ImportKind {
712 Plain,
714 Glob,
716 TypeOnly,
718}
719
720impl Use {
721 pub fn expand(
723 &self,
724 mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
725 ) {
726 self.use_tree.expand_impl(None, &mut 0, &mut cb)
727 }
728}
729
730impl UseTree {
731 pub fn kind(&self) -> &UseTreeKind {
733 &self.kind
734 }
735
736 fn expand_impl(
737 &self,
738 prefix: Option<ModPath>,
739 counting_index: &mut u32,
740 cb: &mut impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
741 ) {
742 fn concat_mod_paths(
743 prefix: Option<ModPath>,
744 path: &ModPath,
745 ) -> Option<(ModPath, ImportKind)> {
746 match (prefix, path.kind) {
747 (None, _) => Some((path.clone(), ImportKind::Plain)),
748 (Some(mut prefix), PathKind::Plain) => {
749 prefix.extend(path.segments().iter().cloned());
750 Some((prefix, ImportKind::Plain))
751 }
752 (Some(mut prefix), PathKind::Super(n)) if n > 0 && prefix.segments().is_empty() => {
753 match &mut prefix.kind {
755 PathKind::Super(m) => {
756 cov_mark::hit!(concat_super_mod_paths);
757 *m += n;
758 prefix.extend(path.segments().iter().cloned());
759 Some((prefix, ImportKind::Plain))
760 }
761 _ => None,
762 }
763 }
764 (Some(prefix), PathKind::SELF) if path.segments().is_empty() => {
765 Some((prefix, ImportKind::TypeOnly))
767 }
768 (Some(_), _) => None,
769 }
770 }
771
772 match &self.kind {
773 UseTreeKind::Single { path, alias } => {
774 if let Some((path, kind)) = concat_mod_paths(prefix, path) {
775 cb(Idx::from_raw(RawIdx::from_u32(*counting_index)), path, kind, alias.clone());
776 }
777 }
778 UseTreeKind::Glob { path: Some(path) } => {
779 if let Some((path, _)) = concat_mod_paths(prefix, path) {
780 cb(
781 Idx::from_raw(RawIdx::from_u32(*counting_index)),
782 path,
783 ImportKind::Glob,
784 None,
785 );
786 }
787 }
788 UseTreeKind::Glob { path: None } => {
789 if let Some(prefix) = prefix {
790 cb(
791 Idx::from_raw(RawIdx::from_u32(*counting_index)),
792 prefix,
793 ImportKind::Glob,
794 None,
795 );
796 }
797 }
798 UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
799 let prefix = match additional_prefix {
800 Some(path) => match concat_mod_paths(prefix, path) {
801 Some((path, ImportKind::Plain)) => Some(path),
802 _ => return,
803 },
804 None => prefix,
805 };
806 for tree in &**list {
807 *counting_index += 1;
808 tree.expand_impl(prefix.clone(), counting_index, cb);
809 }
810 }
811 }
812 }
813}