@@ -578,35 +578,32 @@ impl HygieneData {
578
578
}
579
579
580
580
// Reserve a new syntax context.
581
- // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls,
582
- // the assert below ensures that it doesn't happen.
583
581
let ctxt = SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) ) ;
584
582
self . syntax_context_data
585
583
. push ( SyntaxContextData { dollar_crate_name : sym:: dummy, ..SyntaxContextData :: root ( ) } ) ;
586
584
self . syntax_context_map . insert ( key, ctxt) ;
587
585
588
- // Opaque and semi-opaque versions of the parent. Note that they may be equal to the
589
- // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
590
- // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques.
586
+ // Get parent data
591
587
let parent_data = & self . syntax_context_data [ parent. 0 as usize ] ;
592
588
assert_ne ! ( parent_data. dollar_crate_name, sym:: dummy) ;
593
589
let parent_opaque = parent_data. opaque ;
594
590
let parent_opaque_and_semiopaque = parent_data. opaque_and_semiopaque ;
595
591
596
- // Evaluate opaque and semi-opaque versions of the new syntax context.
592
+ // Evaluate opaque and semi-opaque versions iteratively to avoid recursive calls
597
593
let ( opaque, opaque_and_semiopaque) = match transparency {
598
594
Transparency :: Transparent => ( parent_opaque, parent_opaque_and_semiopaque) ,
599
- Transparency :: SemiOpaque => (
600
- parent_opaque,
601
- // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
602
- self . alloc_ctxt ( parent_opaque_and_semiopaque, expn_id, transparency) ,
603
- ) ,
604
- Transparency :: Opaque => (
605
- // Will be the same as `ctxt` if the expn chain contains only opaques.
606
- self . alloc_ctxt ( parent_opaque, expn_id, transparency) ,
607
- // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
608
- self . alloc_ctxt ( parent_opaque_and_semiopaque, expn_id, transparency) ,
609
- ) ,
595
+ Transparency :: SemiOpaque => {
596
+ let opaque = parent_opaque;
597
+ let semi_opaque =
598
+ self . alloc_ctxt_if_needed ( parent_opaque_and_semiopaque, expn_id, transparency) ;
599
+ ( opaque, semi_opaque)
600
+ }
601
+ Transparency :: Opaque => {
602
+ let opaque = self . alloc_ctxt_if_needed ( parent_opaque, expn_id, transparency) ;
603
+ let semi_opaque =
604
+ self . alloc_ctxt_if_needed ( parent_opaque_and_semiopaque, expn_id, transparency) ;
605
+ ( opaque, semi_opaque)
606
+ }
610
607
} ;
611
608
612
609
// Fill the full data, now that we have it.
@@ -620,6 +617,31 @@ impl HygieneData {
620
617
} ;
621
618
ctxt
622
619
}
620
+
621
+ /// Helper to allocate context only if it would be different from the current one.
622
+ /// This avoids unnecessary recursive calls in common cases.
623
+ #[ inline]
624
+ fn alloc_ctxt_if_needed (
625
+ & mut self ,
626
+ parent : SyntaxContext ,
627
+ expn_id : ExpnId ,
628
+ transparency : Transparency ,
629
+ ) -> SyntaxContext {
630
+ // Fast path: if parent would be the same, return current context being built
631
+ let current_idx = self . syntax_context_data . len ( ) - 1 ;
632
+ if parent. 0 as usize == current_idx {
633
+ return SyntaxContext :: from_usize ( current_idx) ;
634
+ }
635
+
636
+ // Check cache first
637
+ let key = ( parent, expn_id, transparency) ;
638
+ if let Some ( ctxt) = self . syntax_context_map . get ( & key) {
639
+ return * ctxt;
640
+ }
641
+
642
+ // Need to compute
643
+ self . alloc_ctxt ( parent, expn_id, transparency)
644
+ }
623
645
}
624
646
625
647
pub fn walk_chain ( span : Span , to : SyntaxContext ) -> Span {
0 commit comments