@@ -75,6 +75,21 @@ pub struct SyntaxContextData {
7575}
7676
7777impl SyntaxContextData {
78+ fn new (
79+ ( parent, outer_expn, outer_transparency) : SyntaxContextKey ,
80+ opaque : SyntaxContext ,
81+ opaque_and_semitransparent : SyntaxContext ,
82+ ) -> SyntaxContextData {
83+ SyntaxContextData {
84+ outer_expn,
85+ outer_transparency,
86+ parent,
87+ opaque,
88+ opaque_and_semitransparent,
89+ dollar_crate_name : kw:: DollarCrate ,
90+ }
91+ }
92+
7893 fn root ( ) -> SyntaxContextData {
7994 SyntaxContextData {
8095 outer_expn : ExpnId :: root ( ) ,
@@ -543,7 +558,7 @@ impl HygieneData {
543558 ) -> SyntaxContext {
544559 assert_ne ! ( expn_id, ExpnId :: root( ) ) ;
545560 if transparency == Transparency :: Opaque {
546- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
561+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
547562 }
548563
549564 let call_site_ctxt = self . expn_data ( expn_id) . call_site . ctxt ( ) ;
@@ -554,7 +569,7 @@ impl HygieneData {
554569 } ;
555570
556571 if call_site_ctxt. is_root ( ) {
557- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
572+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
558573 }
559574
560575 // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
@@ -567,74 +582,60 @@ impl HygieneData {
567582 //
568583 // See the example at `test/ui/hygiene/legacy_interaction.rs`.
569584 for ( expn_id, transparency) in self . marks ( ctxt) {
570- call_site_ctxt = self . apply_mark_internal ( call_site_ctxt, expn_id, transparency) ;
585+ call_site_ctxt = self . alloc_ctxt ( call_site_ctxt, expn_id, transparency) ;
571586 }
572- self . apply_mark_internal ( call_site_ctxt, expn_id, transparency)
587+ self . alloc_ctxt ( call_site_ctxt, expn_id, transparency)
573588 }
574589
575- fn apply_mark_internal (
590+ /// Allocate a new context with the given key, or retrieve it from cache if the given key
591+ /// already exists. The auxiliary fields are calculated from the key.
592+ fn alloc_ctxt (
576593 & mut self ,
577- ctxt : SyntaxContext ,
594+ parent : SyntaxContext ,
578595 expn_id : ExpnId ,
579596 transparency : Transparency ,
580597 ) -> SyntaxContext {
581- let syntax_context_data = & mut self . syntax_context_data ;
582- debug_assert ! ( !syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
583- let mut opaque = syntax_context_data[ ctxt. 0 as usize ] . opaque ;
584- let mut opaque_and_semitransparent =
585- syntax_context_data[ ctxt. 0 as usize ] . opaque_and_semitransparent ;
586-
587- if transparency >= Transparency :: Opaque {
588- let parent = opaque;
589- opaque = * self
590- . syntax_context_map
591- . entry ( ( parent, expn_id, transparency) )
592- . or_insert_with ( || {
593- let new_opaque = SyntaxContext :: from_usize ( syntax_context_data. len ( ) ) ;
594- syntax_context_data. push ( SyntaxContextData {
595- outer_expn : expn_id,
596- outer_transparency : transparency,
597- parent,
598- opaque : new_opaque,
599- opaque_and_semitransparent : new_opaque,
600- dollar_crate_name : kw:: DollarCrate ,
601- } ) ;
602- new_opaque
603- } ) ;
604- }
598+ debug_assert ! ( !self . syntax_context_data[ parent. 0 as usize ] . is_decode_placeholder( ) ) ;
605599
606- if transparency >= Transparency :: SemiTransparent {
607- let parent = opaque_and_semitransparent;
608- opaque_and_semitransparent = * self
609- . syntax_context_map
610- . entry ( ( parent, expn_id, transparency) )
611- . or_insert_with ( || {
612- let new_opaque_and_semitransparent =
613- SyntaxContext :: from_usize ( syntax_context_data. len ( ) ) ;
614- syntax_context_data. push ( SyntaxContextData {
615- outer_expn : expn_id,
616- outer_transparency : transparency,
617- parent,
618- opaque,
619- opaque_and_semitransparent : new_opaque_and_semitransparent,
620- dollar_crate_name : kw:: DollarCrate ,
621- } ) ;
622- new_opaque_and_semitransparent
623- } ) ;
600+ // Look into the cache first.
601+ let key = ( parent, expn_id, transparency) ;
602+ if let Some ( ctxt) = self . syntax_context_map . get ( & key) {
603+ return * ctxt;
624604 }
625605
626- let parent = ctxt;
627- * self . syntax_context_map . entry ( ( parent, expn_id, transparency) ) . or_insert_with ( || {
628- syntax_context_data. push ( SyntaxContextData {
629- outer_expn : expn_id,
630- outer_transparency : transparency,
631- parent,
632- opaque,
633- opaque_and_semitransparent,
634- dollar_crate_name : kw:: DollarCrate ,
635- } ) ;
636- SyntaxContext :: from_usize ( syntax_context_data. len ( ) - 1 )
637- } )
606+ // Reserve a new syntax context.
607+ let ctxt = SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) ) ;
608+ self . syntax_context_data . push ( SyntaxContextData :: decode_placeholder ( ) ) ;
609+ self . syntax_context_map . insert ( key, ctxt) ;
610+
611+ // Opaque and semi-transparent versions of the parent. Note that they may be equal to the
612+ // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
613+ // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques
614+ // and semi-transparents.
615+ let parent_opaque = self . syntax_context_data [ parent. 0 as usize ] . opaque ;
616+ let parent_opaque_and_semitransparent =
617+ self . syntax_context_data [ parent. 0 as usize ] . opaque_and_semitransparent ;
618+
619+ // Evaluate opaque and semi-transparent versions of the new syntax context.
620+ let ( opaque, opaque_and_semitransparent) = match transparency {
621+ Transparency :: Transparent => ( parent_opaque, parent_opaque_and_semitransparent) ,
622+ Transparency :: SemiTransparent => (
623+ parent_opaque,
624+ // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
625+ self . alloc_ctxt ( parent_opaque_and_semitransparent, expn_id, transparency) ,
626+ ) ,
627+ Transparency :: Opaque => (
628+ // Will be the same as `ctxt` if the expn chain contains only opaques.
629+ self . alloc_ctxt ( parent_opaque, expn_id, transparency) ,
630+ // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
631+ self . alloc_ctxt ( parent_opaque_and_semitransparent, expn_id, transparency) ,
632+ ) ,
633+ } ;
634+
635+ // Fill the full data, now that we have it.
636+ self . syntax_context_data [ ctxt. as_u32 ( ) as usize ] =
637+ SyntaxContextData :: new ( key, opaque, opaque_and_semitransparent) ;
638+ ctxt
638639 }
639640}
640641
0 commit comments