@@ -67,21 +67,32 @@ pub struct SyntaxContextData {
6767 outer_transparency : Transparency ,
6868 parent : SyntaxContext ,
6969 /// This context, but with all transparent and semi-transparent expansions filtered away.
70- opaque : SyntaxContext ,
70+ opaque : Option < SyntaxContext > ,
7171 /// This context, but with all transparent expansions filtered away.
72- opaque_and_semitransparent : SyntaxContext ,
72+ opaque_and_semitransparent : Option < SyntaxContext > ,
7373 /// Name of the crate to which `$crate` with this context would resolve.
7474 dollar_crate_name : Symbol ,
7575}
7676
7777impl SyntaxContextData {
78+ fn from_key ( ( parent, outer_expn, outer_transparency) : SyntaxContextKey ) -> SyntaxContextData {
79+ SyntaxContextData {
80+ outer_expn,
81+ outer_transparency,
82+ parent,
83+ opaque : None ,
84+ opaque_and_semitransparent : None ,
85+ dollar_crate_name : kw:: DollarCrate ,
86+ }
87+ }
88+
7889 fn root ( ) -> SyntaxContextData {
7990 SyntaxContextData {
8091 outer_expn : ExpnId :: root ( ) ,
8192 outer_transparency : Transparency :: Opaque ,
8293 parent : SyntaxContext :: root ( ) ,
83- opaque : SyntaxContext :: root ( ) ,
84- opaque_and_semitransparent : SyntaxContext :: root ( ) ,
94+ opaque : Some ( SyntaxContext :: root ( ) ) ,
95+ opaque_and_semitransparent : Some ( SyntaxContext :: root ( ) ) ,
8596 dollar_crate_name : kw:: DollarCrate ,
8697 }
8798 }
@@ -447,14 +458,43 @@ impl HygieneData {
447458 }
448459 }
449460
450- fn normalize_to_macros_2_0 ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
461+ fn normalize_to_macros_2_0 ( & mut self , ctxt : SyntaxContext ) -> SyntaxContext {
451462 debug_assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
452- self . syntax_context_data [ ctxt. 0 as usize ] . opaque
463+ if let Some ( opaque) = self . syntax_context_data [ ctxt. 0 as usize ] . opaque {
464+ return opaque;
465+ }
466+
467+ let SyntaxContextData { outer_expn, outer_transparency, parent, .. } =
468+ self . syntax_context_data [ ctxt. 0 as usize ] ;
469+ let parent_opaque = self . normalize_to_macros_2_0 ( parent) ;
470+ let opaque = match outer_transparency {
471+ Transparency :: Transparent | Transparency :: SemiTransparent => parent_opaque,
472+ Transparency :: Opaque => self . alloc_ctxt ( parent_opaque, outer_expn, outer_transparency) ,
473+ } ;
474+ self . syntax_context_data [ ctxt. 0 as usize ] . opaque = Some ( opaque) ;
475+ opaque
453476 }
454477
455- fn normalize_to_macro_rules ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
478+ fn normalize_to_macro_rules ( & mut self , ctxt : SyntaxContext ) -> SyntaxContext {
456479 debug_assert ! ( !self . syntax_context_data[ ctxt. 0 as usize ] . is_decode_placeholder( ) ) ;
457- self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semitransparent
480+ if let Some ( opaque_and_semitransparent) =
481+ self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semitransparent
482+ {
483+ return opaque_and_semitransparent;
484+ }
485+
486+ let SyntaxContextData { outer_expn, outer_transparency, parent, .. } =
487+ self . syntax_context_data [ ctxt. 0 as usize ] ;
488+ let parent_opaque_and_semitransparent = self . normalize_to_macro_rules ( parent) ;
489+ let opaque_and_semitransparent = match outer_transparency {
490+ Transparency :: Transparent => parent_opaque_and_semitransparent,
491+ Transparency :: SemiTransparent | Transparency :: Opaque => {
492+ self . alloc_ctxt ( parent_opaque_and_semitransparent, outer_expn, outer_transparency)
493+ }
494+ } ;
495+ self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semitransparent =
496+ Some ( opaque_and_semitransparent) ;
497+ opaque_and_semitransparent
458498 }
459499
460500 fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
@@ -543,7 +583,7 @@ impl HygieneData {
543583 ) -> SyntaxContext {
544584 assert_ne ! ( expn_id, ExpnId :: root( ) ) ;
545585 if transparency == Transparency :: Opaque {
546- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
586+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
547587 }
548588
549589 let call_site_ctxt = self . expn_data ( expn_id) . call_site . ctxt ( ) ;
@@ -554,7 +594,7 @@ impl HygieneData {
554594 } ;
555595
556596 if call_site_ctxt. is_root ( ) {
557- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
597+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
558598 }
559599
560600 // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
@@ -567,73 +607,25 @@ impl HygieneData {
567607 //
568608 // See the example at `test/ui/hygiene/legacy_interaction.rs`.
569609 for ( expn_id, transparency) in self . marks ( ctxt) {
570- call_site_ctxt = self . apply_mark_internal ( call_site_ctxt, expn_id, transparency) ;
610+ call_site_ctxt = self . alloc_ctxt ( call_site_ctxt, expn_id, transparency) ;
571611 }
572- self . apply_mark_internal ( call_site_ctxt, expn_id, transparency)
612+ self . alloc_ctxt ( call_site_ctxt, expn_id, transparency)
573613 }
574614
575- fn apply_mark_internal (
615+ /// Allocate a new context with the given key, or retrieve it from cache if the given key
616+ /// already exists. The auxiliary fields are calculated from the key.
617+ fn alloc_ctxt (
576618 & mut self ,
577- ctxt : SyntaxContext ,
619+ parent : SyntaxContext ,
578620 expn_id : ExpnId ,
579621 transparency : Transparency ,
580622 ) -> 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- }
623+ debug_assert ! ( !self . syntax_context_data[ parent. 0 as usize ] . is_decode_placeholder( ) ) ;
605624
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- } ) ;
624- }
625-
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 )
625+ let key = ( parent, expn_id, transparency) ;
626+ * self . syntax_context_map . entry ( key) . or_insert_with ( || {
627+ self . syntax_context_data . push ( SyntaxContextData :: from_key ( key) ) ;
628+ SyntaxContext :: from_usize ( self . syntax_context_data . len ( ) - 1 )
637629 } )
638630 }
639631}
0 commit comments