@@ -27,16 +27,17 @@ use std::fmt;
27
27
28
28
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
29
29
#[ derive( Clone , Copy , PartialEq , Eq , Default , PartialOrd , Ord , Hash ) ]
30
- pub struct SyntaxContext ( pub ( super ) u32 ) ;
30
+ pub struct SyntaxContext ( u32 ) ;
31
31
32
32
#[ derive( Copy , Clone , Debug ) ]
33
- pub struct SyntaxContextData {
34
- pub outer_mark : Mark ,
35
- pub prev_ctxt : SyntaxContext ,
33
+ struct SyntaxContextData {
34
+ outer_mark : Mark ,
35
+ transparency : Transparency ,
36
+ prev_ctxt : SyntaxContext ,
36
37
// This context, but with all transparent and semi-transparent marks filtered away.
37
- pub opaque : SyntaxContext ,
38
+ opaque : SyntaxContext ,
38
39
// This context, but with all transparent marks filtered away.
39
- pub opaque_and_semitransparent : SyntaxContext ,
40
+ opaque_and_semitransparent : SyntaxContext ,
40
41
}
41
42
42
43
/// A mark is a unique id associated with a macro expansion.
@@ -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
@@ -198,26 +197,27 @@ impl Mark {
198
197
}
199
198
200
199
#[ derive( Debug ) ]
201
- pub struct HygieneData {
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
208
207
impl HygieneData {
209
- pub fn new ( ) -> Self {
208
+ crate fn new ( ) -> Self {
210
209
HygieneData {
211
210
marks : vec ! [ MarkData {
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 ) ,
@@ -249,6 +249,14 @@ impl SyntaxContext {
249
249
SyntaxContext ( 0 )
250
250
}
251
251
252
+ crate fn as_u32 ( self ) -> u32 {
253
+ self . 0
254
+ }
255
+
256
+ crate fn from_u32 ( raw : u32 ) -> SyntaxContext {
257
+ SyntaxContext ( raw)
258
+ }
259
+
252
260
// Allocate a new SyntaxContext with the given ExpnInfo. This is used when
253
261
// deserializing Spans from the incr. comp. cache.
254
262
// FIXME(mw): This method does not restore MarkData::parent or
@@ -259,7 +267,7 @@ impl SyntaxContext {
259
267
HygieneData :: with ( |data| {
260
268
data. marks . push ( MarkData {
261
269
parent : Mark :: root ( ) ,
262
- transparency : Transparency :: SemiTransparent ,
270
+ default_transparency : Transparency :: SemiTransparent ,
263
271
is_builtin : false ,
264
272
expn_info : Some ( expansion_info) ,
265
273
} ) ;
@@ -268,6 +276,7 @@ impl SyntaxContext {
268
276
269
277
data. syntax_contexts . push ( SyntaxContextData {
270
278
outer_mark : mark,
279
+ transparency : Transparency :: SemiTransparent ,
271
280
prev_ctxt : SyntaxContext :: empty ( ) ,
272
281
opaque : SyntaxContext :: empty ( ) ,
273
282
opaque_and_semitransparent : SyntaxContext :: empty ( ) ,
@@ -276,22 +285,31 @@ impl SyntaxContext {
276
285
} )
277
286
}
278
287
279
- /// Extend a syntax context with a given mark
280
288
pub fn apply_mark ( self , mark : Mark ) -> SyntaxContext {
281
- if mark. transparency ( ) == Transparency :: Opaque {
282
- 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) ;
283
301
}
284
302
285
303
let call_site_ctxt =
286
304
mark. expn_info ( ) . map_or ( SyntaxContext :: empty ( ) , |info| info. call_site . ctxt ( ) ) ;
287
- let call_site_ctxt = if mark . transparency ( ) == Transparency :: SemiTransparent {
305
+ let call_site_ctxt = if transparency == Transparency :: SemiTransparent {
288
306
call_site_ctxt. modern ( )
289
307
} else {
290
308
call_site_ctxt. modern_and_legacy ( )
291
309
} ;
292
310
293
311
if call_site_ctxt == SyntaxContext :: empty ( ) {
294
- return self . apply_mark_internal ( mark) ;
312
+ return self . apply_mark_internal ( mark, transparency ) ;
295
313
}
296
314
297
315
// Otherwise, `mark` is a macros 1.0 definition and the call site is in a
@@ -304,27 +322,26 @@ impl SyntaxContext {
304
322
//
305
323
// See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
306
324
let mut ctxt = call_site_ctxt;
307
- for mark in self . marks ( ) {
308
- ctxt = ctxt. apply_mark_internal ( mark) ;
325
+ for ( mark, transparency ) in self . marks ( ) {
326
+ ctxt = ctxt. apply_mark_internal ( mark, transparency ) ;
309
327
}
310
- ctxt. apply_mark_internal ( mark)
328
+ ctxt. apply_mark_internal ( mark, transparency )
311
329
}
312
330
313
- fn apply_mark_internal ( self , mark : Mark ) -> SyntaxContext {
331
+ fn apply_mark_internal ( self , mark : Mark , transparency : Transparency ) -> SyntaxContext {
314
332
HygieneData :: with ( |data| {
315
333
let syntax_contexts = & mut data. syntax_contexts ;
316
- let transparency = data. marks [ mark. 0 as usize ] . transparency ;
317
-
318
334
let mut opaque = syntax_contexts[ self . 0 as usize ] . opaque ;
319
335
let mut opaque_and_semitransparent =
320
336
syntax_contexts[ self . 0 as usize ] . opaque_and_semitransparent ;
321
337
322
338
if transparency >= Transparency :: Opaque {
323
339
let prev_ctxt = opaque;
324
- opaque = * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
340
+ opaque = * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
325
341
let new_opaque = SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
326
342
syntax_contexts. push ( SyntaxContextData {
327
343
outer_mark : mark,
344
+ transparency,
328
345
prev_ctxt,
329
346
opaque : new_opaque,
330
347
opaque_and_semitransparent : new_opaque,
@@ -336,11 +353,12 @@ impl SyntaxContext {
336
353
if transparency >= Transparency :: SemiTransparent {
337
354
let prev_ctxt = opaque_and_semitransparent;
338
355
opaque_and_semitransparent =
339
- * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
356
+ * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
340
357
let new_opaque_and_semitransparent =
341
358
SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
342
359
syntax_contexts. push ( SyntaxContextData {
343
360
outer_mark : mark,
361
+ transparency,
344
362
prev_ctxt,
345
363
opaque,
346
364
opaque_and_semitransparent : new_opaque_and_semitransparent,
@@ -350,11 +368,12 @@ impl SyntaxContext {
350
368
}
351
369
352
370
let prev_ctxt = self ;
353
- * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
371
+ * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
354
372
let new_opaque_and_semitransparent_and_transparent =
355
373
SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
356
374
syntax_contexts. push ( SyntaxContextData {
357
375
outer_mark : mark,
376
+ transparency,
358
377
prev_ctxt,
359
378
opaque,
360
379
opaque_and_semitransparent,
@@ -388,12 +407,13 @@ impl SyntaxContext {
388
407
} )
389
408
}
390
409
391
- pub fn marks ( mut self ) -> Vec < Mark > {
410
+ pub fn marks ( mut self ) -> Vec < ( Mark , Transparency ) > {
392
411
HygieneData :: with ( |data| {
393
412
let mut marks = Vec :: new ( ) ;
394
413
while self != SyntaxContext :: empty ( ) {
395
- marks. push ( data. syntax_contexts [ self . 0 as usize ] . outer_mark ) ;
396
- 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 ;
397
417
}
398
418
marks. reverse ( ) ;
399
419
marks
0 commit comments