@@ -67,21 +67,32 @@ pub struct SyntaxContextData {
67
67
outer_transparency : Transparency ,
68
68
parent : SyntaxContext ,
69
69
/// This context, but with all transparent and semi-transparent expansions filtered away.
70
- opaque : SyntaxContext ,
70
+ opaque : Option < SyntaxContext > ,
71
71
/// This context, but with all transparent expansions filtered away.
72
- opaque_and_semitransparent : SyntaxContext ,
72
+ opaque_and_semitransparent : Option < SyntaxContext > ,
73
73
/// Name of the crate to which `$crate` with this context would resolve.
74
74
dollar_crate_name : Symbol ,
75
75
}
76
76
77
77
impl 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
+
78
89
fn root ( ) -> SyntaxContextData {
79
90
SyntaxContextData {
80
91
outer_expn : ExpnId :: root ( ) ,
81
92
outer_transparency : Transparency :: Opaque ,
82
93
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 ( ) ) ,
85
96
dollar_crate_name : kw:: DollarCrate ,
86
97
}
87
98
}
@@ -447,14 +458,43 @@ impl HygieneData {
447
458
}
448
459
}
449
460
450
- fn normalize_to_macros_2_0 ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
461
+ fn normalize_to_macros_2_0 ( & mut self , ctxt : SyntaxContext ) -> SyntaxContext {
451
462
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
453
476
}
454
477
455
- fn normalize_to_macro_rules ( & self , ctxt : SyntaxContext ) -> SyntaxContext {
478
+ fn normalize_to_macro_rules ( & mut self , ctxt : SyntaxContext ) -> SyntaxContext {
456
479
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
458
498
}
459
499
460
500
fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
@@ -543,7 +583,7 @@ impl HygieneData {
543
583
) -> SyntaxContext {
544
584
assert_ne ! ( expn_id, ExpnId :: root( ) ) ;
545
585
if transparency == Transparency :: Opaque {
546
- return self . apply_mark_internal ( ctxt, expn_id, transparency) ;
586
+ return self . alloc_ctxt ( ctxt, expn_id, transparency) ;
547
587
}
548
588
549
589
let call_site_ctxt = self . expn_data ( expn_id) . call_site . ctxt ( ) ;
@@ -554,7 +594,7 @@ impl HygieneData {
554
594
} ;
555
595
556
596
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) ;
558
598
}
559
599
560
600
// Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
@@ -567,73 +607,25 @@ impl HygieneData {
567
607
//
568
608
// See the example at `test/ui/hygiene/legacy_interaction.rs`.
569
609
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) ;
571
611
}
572
- self . apply_mark_internal ( call_site_ctxt, expn_id, transparency)
612
+ self . alloc_ctxt ( call_site_ctxt, expn_id, transparency)
573
613
}
574
614
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 (
576
618
& mut self ,
577
- ctxt : SyntaxContext ,
619
+ parent : SyntaxContext ,
578
620
expn_id : ExpnId ,
579
621
transparency : Transparency ,
580
622
) -> 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( ) ) ;
605
624
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 )
637
629
} )
638
630
}
639
631
}
0 commit comments