@@ -33,14 +33,17 @@ pub struct SyntaxContext(pub(super) u32);
3333pub struct SyntaxContextData {
3434 pub outer_mark : Mark ,
3535 pub prev_ctxt : SyntaxContext ,
36- pub modern : SyntaxContext ,
36+ // This context, but with all transparent and semi-transparent marks filtered away.
37+ pub opaque : SyntaxContext ,
38+ // This context, but with all transparent marks filtered away.
39+ pub opaque_and_semitransparent : SyntaxContext ,
3740}
3841
3942/// A mark is a unique id associated with a macro expansion.
4043#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug , RustcEncodable , RustcDecodable ) ]
4144pub struct Mark ( u32 ) ;
4245
43- #[ derive( Debug ) ]
46+ #[ derive( Clone , Debug ) ]
4447struct MarkData {
4548 parent : Mark ,
4649 transparency : Transparency ,
@@ -50,7 +53,7 @@ struct MarkData {
5053
5154/// A property of a macro expansion that determines how identifiers
5255/// produced by that expansion are resolved.
53- #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
56+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Debug ) ]
5457pub enum Transparency {
5558 /// Identifier produced by a transparent expansion is always resolved at call-site.
5659 /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -69,16 +72,26 @@ pub enum Transparency {
6972}
7073
7174impl Mark {
75+ fn fresh_with_data ( mark_data : MarkData , data : & mut HygieneData ) -> Self {
76+ data. marks . push ( mark_data) ;
77+ Mark ( data. marks . len ( ) as u32 - 1 )
78+ }
79+
7280 pub fn fresh ( parent : Mark ) -> Self {
7381 HygieneData :: with ( |data| {
74- data . marks . push ( MarkData {
82+ Mark :: fresh_with_data ( MarkData {
7583 parent,
7684 // By default expansions behave like `macro_rules`.
7785 transparency : Transparency :: SemiTransparent ,
7886 is_builtin : false ,
7987 expn_info : None ,
80- } ) ;
81- Mark ( data. marks . len ( ) as u32 - 1 )
88+ } , data)
89+ } )
90+ }
91+
92+ pub fn fresh_cloned ( clone_from : Mark ) -> Self {
93+ HygieneData :: with ( |data| {
94+ Mark :: fresh_with_data ( data. marks [ clone_from. 0 as usize ] . clone ( ) , data)
8295 } )
8396 }
8497
@@ -207,7 +220,8 @@ impl HygieneData {
207220 syntax_contexts : vec ! [ SyntaxContextData {
208221 outer_mark: Mark :: root( ) ,
209222 prev_ctxt: SyntaxContext ( 0 ) ,
210- modern: SyntaxContext ( 0 ) ,
223+ opaque: SyntaxContext ( 0 ) ,
224+ opaque_and_semitransparent: SyntaxContext ( 0 ) ,
211225 } ] ,
212226 markings : HashMap :: new ( ) ,
213227 default_edition : Edition :: Edition2015 ,
@@ -239,7 +253,7 @@ impl SyntaxContext {
239253 // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
240254 // deserializing Spans from the incr. comp. cache.
241255 // FIXME(mw): This method does not restore MarkData::parent or
242- // SyntaxContextData::prev_ctxt or SyntaxContextData::modern . These things
256+ // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque . These things
243257 // don't seem to be used after HIR lowering, so everything should be fine
244258 // as long as incremental compilation does not kick in before that.
245259 pub fn allocate_directly ( expansion_info : ExpnInfo ) -> Self {
@@ -256,7 +270,8 @@ impl SyntaxContext {
256270 data. syntax_contexts . push ( SyntaxContextData {
257271 outer_mark : mark,
258272 prev_ctxt : SyntaxContext :: empty ( ) ,
259- modern : SyntaxContext :: empty ( ) ,
273+ opaque : SyntaxContext :: empty ( ) ,
274+ opaque_and_semitransparent : SyntaxContext :: empty ( ) ,
260275 } ) ;
261276 SyntaxContext ( data. syntax_contexts . len ( ) as u32 - 1 )
262277 } )
@@ -269,7 +284,13 @@ impl SyntaxContext {
269284 }
270285
271286 let call_site_ctxt =
272- mark. expn_info ( ) . map_or ( SyntaxContext :: empty ( ) , |info| info. call_site . ctxt ( ) ) . modern ( ) ;
287+ mark. expn_info ( ) . map_or ( SyntaxContext :: empty ( ) , |info| info. call_site . ctxt ( ) ) ;
288+ let call_site_ctxt = if mark. transparency ( ) == Transparency :: SemiTransparent {
289+ call_site_ctxt. modern ( )
290+ } else {
291+ call_site_ctxt. modern_and_legacy ( )
292+ } ;
293+
273294 if call_site_ctxt == SyntaxContext :: empty ( ) {
274295 return self . apply_mark_internal ( mark) ;
275296 }
@@ -293,26 +314,53 @@ impl SyntaxContext {
293314 fn apply_mark_internal ( self , mark : Mark ) -> SyntaxContext {
294315 HygieneData :: with ( |data| {
295316 let syntax_contexts = & mut data. syntax_contexts ;
296- let mut modern = syntax_contexts[ self . 0 as usize ] . modern ;
297- if data. marks [ mark. 0 as usize ] . transparency == Transparency :: Opaque {
298- modern = * data. markings . entry ( ( modern, mark) ) . or_insert_with ( || {
299- let len = syntax_contexts. len ( ) as u32 ;
317+ let transparency = data. marks [ mark. 0 as usize ] . transparency ;
318+
319+ let mut opaque = syntax_contexts[ self . 0 as usize ] . opaque ;
320+ let mut opaque_and_semitransparent =
321+ syntax_contexts[ self . 0 as usize ] . opaque_and_semitransparent ;
322+
323+ if transparency >= Transparency :: Opaque {
324+ let prev_ctxt = opaque;
325+ opaque = * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
326+ let new_opaque = SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
327+ syntax_contexts. push ( SyntaxContextData {
328+ outer_mark : mark,
329+ prev_ctxt,
330+ opaque : new_opaque,
331+ opaque_and_semitransparent : new_opaque,
332+ } ) ;
333+ new_opaque
334+ } ) ;
335+ }
336+
337+ if transparency >= Transparency :: SemiTransparent {
338+ let prev_ctxt = opaque_and_semitransparent;
339+ opaque_and_semitransparent =
340+ * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
341+ let new_opaque_and_semitransparent =
342+ SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
300343 syntax_contexts. push ( SyntaxContextData {
301344 outer_mark : mark,
302- prev_ctxt : modern,
303- modern : SyntaxContext ( len) ,
345+ prev_ctxt,
346+ opaque,
347+ opaque_and_semitransparent : new_opaque_and_semitransparent,
304348 } ) ;
305- SyntaxContext ( len )
349+ new_opaque_and_semitransparent
306350 } ) ;
307351 }
308352
309- * data. markings . entry ( ( self , mark) ) . or_insert_with ( || {
353+ let prev_ctxt = self ;
354+ * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
355+ let new_opaque_and_semitransparent_and_transparent =
356+ SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
310357 syntax_contexts. push ( SyntaxContextData {
311358 outer_mark : mark,
312- prev_ctxt : self ,
313- modern,
359+ prev_ctxt,
360+ opaque,
361+ opaque_and_semitransparent,
314362 } ) ;
315- SyntaxContext ( syntax_contexts . len ( ) as u32 - 1 )
363+ new_opaque_and_semitransparent_and_transparent
316364 } )
317365 } )
318366 }
@@ -452,7 +500,12 @@ impl SyntaxContext {
452500
453501 #[ inline]
454502 pub fn modern ( self ) -> SyntaxContext {
455- HygieneData :: with ( |data| data. syntax_contexts [ self . 0 as usize ] . modern )
503+ HygieneData :: with ( |data| data. syntax_contexts [ self . 0 as usize ] . opaque )
504+ }
505+
506+ #[ inline]
507+ pub fn modern_and_legacy ( self ) -> SyntaxContext {
508+ HygieneData :: with ( |data| data. syntax_contexts [ self . 0 as usize ] . opaque_and_semitransparent )
456509 }
457510
458511 #[ inline]
0 commit comments