@@ -322,6 +322,7 @@ impl ExpnId {
322
322
323
323
/// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
324
324
/// `expn_id.is_descendant_of(ctxt.outer_expn())`.
325
+ #[ inline]
325
326
pub fn outer_expn_is_descendant_of ( self , ctxt : SyntaxContext ) -> bool {
326
327
HygieneData :: with ( |data| data. is_descendant_of ( self , data. outer_expn ( ctxt) ) )
327
328
}
@@ -437,23 +438,28 @@ impl HygieneData {
437
438
}
438
439
}
439
440
441
+ #[ inline]
440
442
fn normalize_to_macros_2_0 ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
441
443
self . syntax_context_data [ ctxt. 0 as usize ] . opaque
442
444
}
443
445
446
+ #[ inline]
444
447
fn normalize_to_macro_rules ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
445
448
self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semiopaque
446
449
}
447
450
451
+ #[ inline]
448
452
fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
449
453
self . syntax_context_data [ ctxt. 0 as usize ] . outer_expn
450
454
}
451
455
456
+ #[ inline]
452
457
fn outer_mark ( & self , ctxt : SyntaxContext ) -> ( ExpnId , Transparency ) {
453
458
let data = & self . syntax_context_data [ ctxt. 0 as usize ] ;
454
459
( data. outer_expn , data. outer_transparency )
455
460
}
456
461
462
+ #[ inline]
457
463
fn parent_ctxt ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
458
464
self . syntax_context_data [ ctxt. 0 as usize ] . parent
459
465
}
@@ -572,35 +578,32 @@ impl HygieneData {
572
578
}
573
579
574
580
// 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.
577
581
let ctxt = SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) ) ;
578
582
self . syntax_context_data
579
583
. push ( SyntaxContextData { dollar_crate_name : sym:: dummy, ..SyntaxContextData :: root ( ) } ) ;
580
584
self . syntax_context_map . insert ( key, ctxt) ;
581
585
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
585
587
let parent_data = & self . syntax_context_data [ parent. 0 as usize ] ;
586
588
assert_ne ! ( parent_data. dollar_crate_name, sym:: dummy) ;
587
589
let parent_opaque = parent_data. opaque ;
588
590
let parent_opaque_and_semiopaque = parent_data. opaque_and_semiopaque ;
589
591
590
- // Evaluate opaque and semi-opaque versions of the new syntax context.
592
+ // Evaluate opaque and semi-opaque versions iteratively to avoid recursive calls
591
593
let ( opaque, opaque_and_semiopaque) = match transparency {
592
594
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
+ }
604
607
} ;
605
608
606
609
// Fill the full data, now that we have it.
@@ -614,6 +617,31 @@ impl HygieneData {
614
617
} ;
615
618
ctxt
616
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
+ }
617
645
}
618
646
619
647
pub fn walk_chain ( span : Span , to : SyntaxContext ) -> Span {
@@ -718,11 +746,13 @@ impl SyntaxContext {
718
746
SyntaxContext ( raw as u32 )
719
747
}
720
748
749
+ #[ inline]
721
750
fn from_usize ( raw : usize ) -> SyntaxContext {
722
751
SyntaxContext ( u32:: try_from ( raw) . unwrap ( ) )
723
752
}
724
753
725
754
/// Extend a syntax context with a given expansion and transparency.
755
+ #[ inline]
726
756
pub fn apply_mark ( self , expn_id : ExpnId , transparency : Transparency ) -> SyntaxContext {
727
757
HygieneData :: with ( |data| data. apply_mark ( self , expn_id, transparency) )
728
758
}
@@ -743,10 +773,12 @@ impl SyntaxContext {
743
773
/// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
744
774
/// invocation of f that created g1.
745
775
/// Returns the mark that was removed.
776
+ #[ inline]
746
777
pub fn remove_mark ( & mut self ) -> ExpnId {
747
778
HygieneData :: with ( |data| data. remove_mark ( self ) . 0 )
748
779
}
749
780
781
+ #[ inline]
750
782
pub fn marks ( self ) -> Vec < ( ExpnId , Transparency ) > {
751
783
HygieneData :: with ( |data| data. marks ( self ) )
752
784
}
@@ -776,11 +808,13 @@ impl SyntaxContext {
776
808
/// ```
777
809
/// This returns the expansion whose definition scope we use to privacy check the resolution,
778
810
/// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
811
+ #[ inline]
779
812
pub fn adjust ( & mut self , expn_id : ExpnId ) -> Option < ExpnId > {
780
813
HygieneData :: with ( |data| data. adjust ( self , expn_id) )
781
814
}
782
815
783
816
/// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
817
+ #[ inline]
784
818
pub ( crate ) fn normalize_to_macros_2_0_and_adjust ( & mut self , expn_id : ExpnId ) -> Option < ExpnId > {
785
819
HygieneData :: with ( |data| {
786
820
* self = data. normalize_to_macros_2_0 ( * self ) ;
@@ -901,10 +935,12 @@ impl SyntaxContext {
901
935
HygieneData :: with ( |data| data. outer_mark ( self ) )
902
936
}
903
937
938
+ #[ inline]
904
939
pub ( crate ) fn dollar_crate_name ( self ) -> Symbol {
905
940
HygieneData :: with ( |data| data. syntax_context_data [ self . 0 as usize ] . dollar_crate_name )
906
941
}
907
942
943
+ #[ inline]
908
944
pub fn edition ( self ) -> Edition {
909
945
HygieneData :: with ( |data| data. expn_data ( data. outer_expn ( self ) ) . edition )
910
946
}
0 commit comments