@@ -322,6 +322,7 @@ impl ExpnId {
322322
323323 /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
324324 /// `expn_id.is_descendant_of(ctxt.outer_expn())`.
325+ #[ inline]
325326 pub fn outer_expn_is_descendant_of ( self , ctxt : SyntaxContext ) -> bool {
326327 HygieneData :: with ( |data| data. is_descendant_of ( self , data. outer_expn ( ctxt) ) )
327328 }
@@ -437,23 +438,28 @@ impl HygieneData {
437438 }
438439 }
439440
441+ #[ inline]
440442 fn normalize_to_macros_2_0 ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
441443 self . syntax_context_data [ ctxt. 0 as usize ] . opaque
442444 }
443445
446+ #[ inline]
444447 fn normalize_to_macro_rules ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
445448 self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semiopaque
446449 }
447450
451+ #[ inline]
448452 fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
449453 self . syntax_context_data [ ctxt. 0 as usize ] . outer_expn
450454 }
451455
456+ #[ inline]
452457 fn outer_mark ( & self , ctxt : SyntaxContext ) -> ( ExpnId , Transparency ) {
453458 let data = & self . syntax_context_data [ ctxt. 0 as usize ] ;
454459 ( data. outer_expn , data. outer_transparency )
455460 }
456461
462+ #[ inline]
457463 fn parent_ctxt ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
458464 self . syntax_context_data [ ctxt. 0 as usize ] . parent
459465 }
@@ -572,35 +578,32 @@ impl HygieneData {
572578 }
573579
574580 // Reserve a new syntax context.
575- // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls,
576- // the assert below ensures that it doesn't happen.
577581 let ctxt = SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) ) ;
578582 self . syntax_context_data
579583 . push ( SyntaxContextData { dollar_crate_name : sym:: dummy, ..SyntaxContextData :: root ( ) } ) ;
580584 self . syntax_context_map . insert ( key, ctxt) ;
581585
582- // Opaque and semi-opaque versions of the parent. Note that they may be equal to the
583- // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
584- // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques.
586+ // Get parent data
585587 let parent_data = & self . syntax_context_data [ parent. 0 as usize ] ;
586588 assert_ne ! ( parent_data. dollar_crate_name, sym:: dummy) ;
587589 let parent_opaque = parent_data. opaque ;
588590 let parent_opaque_and_semiopaque = parent_data. opaque_and_semiopaque ;
589591
590- // Evaluate opaque and semi-opaque versions of the new syntax context.
592+ // Evaluate opaque and semi-opaque versions iteratively to avoid recursive calls
591593 let ( opaque, opaque_and_semiopaque) = match transparency {
592594 Transparency :: Transparent => ( parent_opaque, parent_opaque_and_semiopaque) ,
593- Transparency :: SemiOpaque => (
594- parent_opaque,
595- // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
596- self . alloc_ctxt ( parent_opaque_and_semiopaque, expn_id, transparency) ,
597- ) ,
598- Transparency :: Opaque => (
599- // Will be the same as `ctxt` if the expn chain contains only opaques.
600- self . alloc_ctxt ( parent_opaque, expn_id, transparency) ,
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- ) ,
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+ }
604607 } ;
605608
606609 // Fill the full data, now that we have it.
@@ -614,6 +617,31 @@ impl HygieneData {
614617 } ;
615618 ctxt
616619 }
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+ }
617645}
618646
619647pub fn walk_chain ( span : Span , to : SyntaxContext ) -> Span {
@@ -718,11 +746,13 @@ impl SyntaxContext {
718746 SyntaxContext ( raw as u32 )
719747 }
720748
749+ #[ inline]
721750 fn from_usize ( raw : usize ) -> SyntaxContext {
722751 SyntaxContext ( u32:: try_from ( raw) . unwrap ( ) )
723752 }
724753
725754 /// Extend a syntax context with a given expansion and transparency.
755+ #[ inline]
726756 pub fn apply_mark ( self , expn_id : ExpnId , transparency : Transparency ) -> SyntaxContext {
727757 HygieneData :: with ( |data| data. apply_mark ( self , expn_id, transparency) )
728758 }
@@ -743,10 +773,12 @@ impl SyntaxContext {
743773 /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
744774 /// invocation of f that created g1.
745775 /// Returns the mark that was removed.
776+ #[ inline]
746777 pub fn remove_mark ( & mut self ) -> ExpnId {
747778 HygieneData :: with ( |data| data. remove_mark ( self ) . 0 )
748779 }
749780
781+ #[ inline]
750782 pub fn marks ( self ) -> Vec < ( ExpnId , Transparency ) > {
751783 HygieneData :: with ( |data| data. marks ( self ) )
752784 }
@@ -776,11 +808,13 @@ impl SyntaxContext {
776808 /// ```
777809 /// This returns the expansion whose definition scope we use to privacy check the resolution,
778810 /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
811+ #[ inline]
779812 pub fn adjust ( & mut self , expn_id : ExpnId ) -> Option < ExpnId > {
780813 HygieneData :: with ( |data| data. adjust ( self , expn_id) )
781814 }
782815
783816 /// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
817+ #[ inline]
784818 pub ( crate ) fn normalize_to_macros_2_0_and_adjust ( & mut self , expn_id : ExpnId ) -> Option < ExpnId > {
785819 HygieneData :: with ( |data| {
786820 * self = data. normalize_to_macros_2_0 ( * self ) ;
@@ -901,10 +935,12 @@ impl SyntaxContext {
901935 HygieneData :: with ( |data| data. outer_mark ( self ) )
902936 }
903937
938+ #[ inline]
904939 pub ( crate ) fn dollar_crate_name ( self ) -> Symbol {
905940 HygieneData :: with ( |data| data. syntax_context_data [ self . 0 as usize ] . dollar_crate_name )
906941 }
907942
943+ #[ inline]
908944 pub fn edition ( self ) -> Edition {
909945 HygieneData :: with ( |data| data. expn_data ( data. outer_expn ( self ) ) . edition )
910946 }
0 commit comments