@@ -32,6 +32,7 @@ pub struct SyntaxContext(u32);
32
32
#[ derive( Copy , Clone , Debug ) ]
33
33
struct SyntaxContextData {
34
34
outer_mark : Mark ,
35
+ transparency : Transparency ,
35
36
prev_ctxt : SyntaxContext ,
36
37
// This context, but with all transparent and semi-transparent marks filtered away.
37
38
opaque : SyntaxContext ,
@@ -46,14 +47,14 @@ pub struct Mark(u32);
46
47
#[ derive( Clone , Debug ) ]
47
48
struct MarkData {
48
49
parent : Mark ,
49
- transparency : Transparency ,
50
+ default_transparency : Transparency ,
50
51
is_builtin : bool ,
51
52
expn_info : Option < ExpnInfo > ,
52
53
}
53
54
54
55
/// A property of a macro expansion that determines how identifiers
55
56
/// produced by that expansion are resolved.
56
- #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Debug ) ]
57
+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Hash , Debug ) ]
57
58
pub enum Transparency {
58
59
/// Identifier produced by a transparent expansion is always resolved at call-site.
59
60
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -81,7 +82,7 @@ impl Mark {
81
82
Mark :: fresh_with_data ( MarkData {
82
83
parent,
83
84
// By default expansions behave like `macro_rules`.
84
- transparency : Transparency :: SemiTransparent ,
85
+ default_transparency : Transparency :: SemiTransparent ,
85
86
is_builtin : false ,
86
87
expn_info : None ,
87
88
} , data)
@@ -127,34 +128,32 @@ impl Mark {
127
128
} )
128
129
}
129
130
131
+ // FIXME: This operation doesn't really make sense when single macro expansion
132
+ // can produce tokens with different transparencies. Figure out how to avoid it.
130
133
pub fn modern ( mut self ) -> Mark {
131
134
HygieneData :: with ( |data| {
132
- while data. marks [ self . 0 as usize ] . transparency != Transparency :: Opaque {
135
+ while data. marks [ self . 0 as usize ] . default_transparency != Transparency :: Opaque {
133
136
self = data. marks [ self . 0 as usize ] . parent ;
134
137
}
135
138
self
136
139
} )
137
140
}
138
141
139
142
#[ inline]
140
- pub fn transparency ( self ) -> Transparency {
141
- assert_ne ! ( self , Mark :: root( ) ) ;
142
- HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . transparency )
143
- }
144
-
145
- #[ inline]
146
- pub fn set_transparency ( self , transparency : Transparency ) {
143
+ pub fn set_default_transparency ( self , transparency : Transparency ) {
147
144
assert_ne ! ( self , Mark :: root( ) ) ;
148
- HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . transparency = transparency)
145
+ HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . default_transparency = transparency)
149
146
}
150
147
151
148
#[ inline]
152
149
pub fn is_builtin ( self ) -> bool {
150
+ assert_ne ! ( self , Mark :: root( ) ) ;
153
151
HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . is_builtin )
154
152
}
155
153
156
154
#[ inline]
157
155
pub fn set_is_builtin ( self , is_builtin : bool ) {
156
+ assert_ne ! ( self , Mark :: root( ) ) ;
158
157
HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . is_builtin = is_builtin)
159
158
}
160
159
@@ -201,7 +200,7 @@ impl Mark {
201
200
crate struct HygieneData {
202
201
marks : Vec < MarkData > ,
203
202
syntax_contexts : Vec < SyntaxContextData > ,
204
- markings : HashMap < ( SyntaxContext , Mark ) , SyntaxContext > ,
203
+ markings : HashMap < ( SyntaxContext , Mark , Transparency ) , SyntaxContext > ,
205
204
default_edition : Edition ,
206
205
}
207
206
@@ -212,12 +211,13 @@ impl HygieneData {
212
211
parent: Mark :: root( ) ,
213
212
// If the root is opaque, then loops searching for an opaque mark
214
213
// will automatically stop after reaching it.
215
- transparency : Transparency :: Opaque ,
214
+ default_transparency : Transparency :: Opaque ,
216
215
is_builtin: true ,
217
216
expn_info: None ,
218
217
} ] ,
219
218
syntax_contexts : vec ! [ SyntaxContextData {
220
219
outer_mark: Mark :: root( ) ,
220
+ transparency: Transparency :: Opaque ,
221
221
prev_ctxt: SyntaxContext ( 0 ) ,
222
222
opaque: SyntaxContext ( 0 ) ,
223
223
opaque_and_semitransparent: SyntaxContext ( 0 ) ,
@@ -267,7 +267,7 @@ impl SyntaxContext {
267
267
HygieneData :: with ( |data| {
268
268
data. marks . push ( MarkData {
269
269
parent : Mark :: root ( ) ,
270
- transparency : Transparency :: SemiTransparent ,
270
+ default_transparency : Transparency :: SemiTransparent ,
271
271
is_builtin : false ,
272
272
expn_info : Some ( expansion_info) ,
273
273
} ) ;
@@ -276,6 +276,7 @@ impl SyntaxContext {
276
276
277
277
data. syntax_contexts . push ( SyntaxContextData {
278
278
outer_mark : mark,
279
+ transparency : Transparency :: SemiTransparent ,
279
280
prev_ctxt : SyntaxContext :: empty ( ) ,
280
281
opaque : SyntaxContext :: empty ( ) ,
281
282
opaque_and_semitransparent : SyntaxContext :: empty ( ) ,
@@ -284,22 +285,31 @@ impl SyntaxContext {
284
285
} )
285
286
}
286
287
287
- /// Extend a syntax context with a given mark
288
288
pub fn apply_mark ( self , mark : Mark ) -> SyntaxContext {
289
- if mark. transparency ( ) == Transparency :: Opaque {
290
- return self . apply_mark_internal ( mark) ;
289
+ assert_ne ! ( mark, Mark :: root( ) ) ;
290
+ self . apply_mark_with_transparency (
291
+ mark, HygieneData :: with ( |data| data. marks [ mark. 0 as usize ] . default_transparency )
292
+ )
293
+ }
294
+
295
+ /// Extend a syntax context with a given mark and transparency
296
+ pub fn apply_mark_with_transparency ( self , mark : Mark , transparency : Transparency )
297
+ -> SyntaxContext {
298
+ assert_ne ! ( mark, Mark :: root( ) ) ;
299
+ if transparency == Transparency :: Opaque {
300
+ return self . apply_mark_internal ( mark, transparency) ;
291
301
}
292
302
293
303
let call_site_ctxt =
294
304
mark. expn_info ( ) . map_or ( SyntaxContext :: empty ( ) , |info| info. call_site . ctxt ( ) ) ;
295
- let call_site_ctxt = if mark . transparency ( ) == Transparency :: SemiTransparent {
305
+ let call_site_ctxt = if transparency == Transparency :: SemiTransparent {
296
306
call_site_ctxt. modern ( )
297
307
} else {
298
308
call_site_ctxt. modern_and_legacy ( )
299
309
} ;
300
310
301
311
if call_site_ctxt == SyntaxContext :: empty ( ) {
302
- return self . apply_mark_internal ( mark) ;
312
+ return self . apply_mark_internal ( mark, transparency ) ;
303
313
}
304
314
305
315
// Otherwise, `mark` is a macros 1.0 definition and the call site is in a
@@ -312,27 +322,26 @@ impl SyntaxContext {
312
322
//
313
323
// See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
314
324
let mut ctxt = call_site_ctxt;
315
- for mark in self . marks ( ) {
316
- ctxt = ctxt. apply_mark_internal ( mark) ;
325
+ for ( mark, transparency ) in self . marks ( ) {
326
+ ctxt = ctxt. apply_mark_internal ( mark, transparency ) ;
317
327
}
318
- ctxt. apply_mark_internal ( mark)
328
+ ctxt. apply_mark_internal ( mark, transparency )
319
329
}
320
330
321
- fn apply_mark_internal ( self , mark : Mark ) -> SyntaxContext {
331
+ fn apply_mark_internal ( self , mark : Mark , transparency : Transparency ) -> SyntaxContext {
322
332
HygieneData :: with ( |data| {
323
333
let syntax_contexts = & mut data. syntax_contexts ;
324
- let transparency = data. marks [ mark. 0 as usize ] . transparency ;
325
-
326
334
let mut opaque = syntax_contexts[ self . 0 as usize ] . opaque ;
327
335
let mut opaque_and_semitransparent =
328
336
syntax_contexts[ self . 0 as usize ] . opaque_and_semitransparent ;
329
337
330
338
if transparency >= Transparency :: Opaque {
331
339
let prev_ctxt = opaque;
332
- opaque = * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
340
+ opaque = * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
333
341
let new_opaque = SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
334
342
syntax_contexts. push ( SyntaxContextData {
335
343
outer_mark : mark,
344
+ transparency,
336
345
prev_ctxt,
337
346
opaque : new_opaque,
338
347
opaque_and_semitransparent : new_opaque,
@@ -344,11 +353,12 @@ impl SyntaxContext {
344
353
if transparency >= Transparency :: SemiTransparent {
345
354
let prev_ctxt = opaque_and_semitransparent;
346
355
opaque_and_semitransparent =
347
- * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
356
+ * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
348
357
let new_opaque_and_semitransparent =
349
358
SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
350
359
syntax_contexts. push ( SyntaxContextData {
351
360
outer_mark : mark,
361
+ transparency,
352
362
prev_ctxt,
353
363
opaque,
354
364
opaque_and_semitransparent : new_opaque_and_semitransparent,
@@ -358,11 +368,12 @@ impl SyntaxContext {
358
368
}
359
369
360
370
let prev_ctxt = self ;
361
- * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
371
+ * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
362
372
let new_opaque_and_semitransparent_and_transparent =
363
373
SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
364
374
syntax_contexts. push ( SyntaxContextData {
365
375
outer_mark : mark,
376
+ transparency,
366
377
prev_ctxt,
367
378
opaque,
368
379
opaque_and_semitransparent,
@@ -396,12 +407,13 @@ impl SyntaxContext {
396
407
} )
397
408
}
398
409
399
- pub fn marks ( mut self ) -> Vec < Mark > {
410
+ pub fn marks ( mut self ) -> Vec < ( Mark , Transparency ) > {
400
411
HygieneData :: with ( |data| {
401
412
let mut marks = Vec :: new ( ) ;
402
413
while self != SyntaxContext :: empty ( ) {
403
- marks. push ( data. syntax_contexts [ self . 0 as usize ] . outer_mark ) ;
404
- self = data. syntax_contexts [ self . 0 as usize ] . prev_ctxt ;
414
+ let ctxt_data = & data. syntax_contexts [ self . 0 as usize ] ;
415
+ marks. push ( ( ctxt_data. outer_mark , ctxt_data. transparency ) ) ;
416
+ self = ctxt_data. prev_ctxt ;
405
417
}
406
418
marks. reverse ( ) ;
407
419
marks
0 commit comments