@@ -75,6 +75,21 @@ pub struct SyntaxContextData {
75
75
}
76
76
77
77
impl 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
+
78
93
fn root ( ) -> SyntaxContextData {
79
94
SyntaxContextData {
80
95
outer_expn : ExpnId :: root ( ) ,
@@ -543,7 +558,7 @@ impl HygieneData {
543
558
) -> SyntaxContext {
544
559
assert_ne ! ( expn_id, ExpnId :: root( ) ) ;
545
560
if transparency == Transparency :: Opaque {
546
- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
561
+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
547
562
}
548
563
549
564
let call_site_ctxt = self . expn_data ( expn_id) . call_site . ctxt ( ) ;
@@ -554,7 +569,7 @@ impl HygieneData {
554
569
} ;
555
570
556
571
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) ;
558
573
}
559
574
560
575
// Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
@@ -567,74 +582,60 @@ impl HygieneData {
567
582
//
568
583
// See the example at `test/ui/hygiene/legacy_interaction.rs`.
569
584
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) ;
571
586
}
572
- self . apply_mark_internal ( call_site_ctxt, expn_id, transparency)
587
+ self . alloc_ctxt ( call_site_ctxt, expn_id, transparency)
573
588
}
574
589
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 (
576
593
& mut self ,
577
- ctxt : SyntaxContext ,
594
+ parent : SyntaxContext ,
578
595
expn_id : ExpnId ,
579
596
transparency : Transparency ,
580
597
) -> 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( ) ) ;
605
599
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;
624
604
}
625
605
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
638
639
}
639
640
}
640
641
0 commit comments