@@ -27,16 +27,17 @@ use std::fmt;
2727
2828/// A SyntaxContext represents a chain of macro expansions (represented by marks).
2929#[ derive( Clone , Copy , PartialEq , Eq , Default , PartialOrd , Ord , Hash ) ]
30- pub struct SyntaxContext ( pub ( super ) u32 ) ;
30+ pub struct SyntaxContext ( u32 ) ;
3131
3232#[ 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 ,
3637 // This context, but with all transparent and semi-transparent marks filtered away.
37- pub opaque : SyntaxContext ,
38+ opaque : SyntaxContext ,
3839 // This context, but with all transparent marks filtered away.
39- pub opaque_and_semitransparent : SyntaxContext ,
40+ opaque_and_semitransparent : SyntaxContext ,
4041}
4142
4243/// A mark is a unique id associated with a macro expansion.
@@ -46,14 +47,14 @@ pub struct Mark(u32);
4647#[ derive( Clone , Debug ) ]
4748struct MarkData {
4849 parent : Mark ,
49- transparency : Transparency ,
50+ default_transparency : Transparency ,
5051 is_builtin : bool ,
5152 expn_info : Option < ExpnInfo > ,
5253}
5354
5455/// A property of a macro expansion that determines how identifiers
5556/// produced by that expansion are resolved.
56- #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Debug ) ]
57+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Hash , Debug ) ]
5758pub enum Transparency {
5859 /// Identifier produced by a transparent expansion is always resolved at call-site.
5960 /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -81,7 +82,7 @@ impl Mark {
8182 Mark :: fresh_with_data ( MarkData {
8283 parent,
8384 // By default expansions behave like `macro_rules`.
84- transparency : Transparency :: SemiTransparent ,
85+ default_transparency : Transparency :: SemiTransparent ,
8586 is_builtin : false ,
8687 expn_info : None ,
8788 } , data)
@@ -127,34 +128,32 @@ impl Mark {
127128 } )
128129 }
129130
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.
130133 pub fn modern ( mut self ) -> Mark {
131134 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 {
133136 self = data. marks [ self . 0 as usize ] . parent ;
134137 }
135138 self
136139 } )
137140 }
138141
139142 #[ 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 ) {
147144 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)
149146 }
150147
151148 #[ inline]
152149 pub fn is_builtin ( self ) -> bool {
150+ assert_ne ! ( self , Mark :: root( ) ) ;
153151 HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . is_builtin )
154152 }
155153
156154 #[ inline]
157155 pub fn set_is_builtin ( self , is_builtin : bool ) {
156+ assert_ne ! ( self , Mark :: root( ) ) ;
158157 HygieneData :: with ( |data| data. marks [ self . 0 as usize ] . is_builtin = is_builtin)
159158 }
160159
@@ -198,26 +197,27 @@ impl Mark {
198197}
199198
200199#[ derive( Debug ) ]
201- pub struct HygieneData {
200+ crate struct HygieneData {
202201 marks : Vec < MarkData > ,
203202 syntax_contexts : Vec < SyntaxContextData > ,
204- markings : HashMap < ( SyntaxContext , Mark ) , SyntaxContext > ,
203+ markings : HashMap < ( SyntaxContext , Mark , Transparency ) , SyntaxContext > ,
205204 default_edition : Edition ,
206205}
207206
208207impl HygieneData {
209- pub fn new ( ) -> Self {
208+ crate fn new ( ) -> Self {
210209 HygieneData {
211210 marks : vec ! [ MarkData {
212211 parent: Mark :: root( ) ,
213212 // If the root is opaque, then loops searching for an opaque mark
214213 // will automatically stop after reaching it.
215- transparency : Transparency :: Opaque ,
214+ default_transparency : Transparency :: Opaque ,
216215 is_builtin: true ,
217216 expn_info: None ,
218217 } ] ,
219218 syntax_contexts : vec ! [ SyntaxContextData {
220219 outer_mark: Mark :: root( ) ,
220+ transparency: Transparency :: Opaque ,
221221 prev_ctxt: SyntaxContext ( 0 ) ,
222222 opaque: SyntaxContext ( 0 ) ,
223223 opaque_and_semitransparent: SyntaxContext ( 0 ) ,
@@ -249,6 +249,14 @@ impl SyntaxContext {
249249 SyntaxContext ( 0 )
250250 }
251251
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+
252260 // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
253261 // deserializing Spans from the incr. comp. cache.
254262 // FIXME(mw): This method does not restore MarkData::parent or
@@ -259,7 +267,7 @@ impl SyntaxContext {
259267 HygieneData :: with ( |data| {
260268 data. marks . push ( MarkData {
261269 parent : Mark :: root ( ) ,
262- transparency : Transparency :: SemiTransparent ,
270+ default_transparency : Transparency :: SemiTransparent ,
263271 is_builtin : false ,
264272 expn_info : Some ( expansion_info) ,
265273 } ) ;
@@ -268,6 +276,7 @@ impl SyntaxContext {
268276
269277 data. syntax_contexts . push ( SyntaxContextData {
270278 outer_mark : mark,
279+ transparency : Transparency :: SemiTransparent ,
271280 prev_ctxt : SyntaxContext :: empty ( ) ,
272281 opaque : SyntaxContext :: empty ( ) ,
273282 opaque_and_semitransparent : SyntaxContext :: empty ( ) ,
@@ -276,22 +285,31 @@ impl SyntaxContext {
276285 } )
277286 }
278287
279- /// Extend a syntax context with a given mark
280288 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) ;
283301 }
284302
285303 let call_site_ctxt =
286304 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 {
288306 call_site_ctxt. modern ( )
289307 } else {
290308 call_site_ctxt. modern_and_legacy ( )
291309 } ;
292310
293311 if call_site_ctxt == SyntaxContext :: empty ( ) {
294- return self . apply_mark_internal ( mark) ;
312+ return self . apply_mark_internal ( mark, transparency ) ;
295313 }
296314
297315 // Otherwise, `mark` is a macros 1.0 definition and the call site is in a
@@ -304,27 +322,26 @@ impl SyntaxContext {
304322 //
305323 // See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
306324 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 ) ;
309327 }
310- ctxt. apply_mark_internal ( mark)
328+ ctxt. apply_mark_internal ( mark, transparency )
311329 }
312330
313- fn apply_mark_internal ( self , mark : Mark ) -> SyntaxContext {
331+ fn apply_mark_internal ( self , mark : Mark , transparency : Transparency ) -> SyntaxContext {
314332 HygieneData :: with ( |data| {
315333 let syntax_contexts = & mut data. syntax_contexts ;
316- let transparency = data. marks [ mark. 0 as usize ] . transparency ;
317-
318334 let mut opaque = syntax_contexts[ self . 0 as usize ] . opaque ;
319335 let mut opaque_and_semitransparent =
320336 syntax_contexts[ self . 0 as usize ] . opaque_and_semitransparent ;
321337
322338 if transparency >= Transparency :: Opaque {
323339 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 ( || {
325341 let new_opaque = SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
326342 syntax_contexts. push ( SyntaxContextData {
327343 outer_mark : mark,
344+ transparency,
328345 prev_ctxt,
329346 opaque : new_opaque,
330347 opaque_and_semitransparent : new_opaque,
@@ -336,11 +353,12 @@ impl SyntaxContext {
336353 if transparency >= Transparency :: SemiTransparent {
337354 let prev_ctxt = opaque_and_semitransparent;
338355 opaque_and_semitransparent =
339- * data. markings . entry ( ( prev_ctxt, mark) ) . or_insert_with ( || {
356+ * data. markings . entry ( ( prev_ctxt, mark, transparency ) ) . or_insert_with ( || {
340357 let new_opaque_and_semitransparent =
341358 SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
342359 syntax_contexts. push ( SyntaxContextData {
343360 outer_mark : mark,
361+ transparency,
344362 prev_ctxt,
345363 opaque,
346364 opaque_and_semitransparent : new_opaque_and_semitransparent,
@@ -350,11 +368,12 @@ impl SyntaxContext {
350368 }
351369
352370 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 ( || {
354372 let new_opaque_and_semitransparent_and_transparent =
355373 SyntaxContext ( syntax_contexts. len ( ) as u32 ) ;
356374 syntax_contexts. push ( SyntaxContextData {
357375 outer_mark : mark,
376+ transparency,
358377 prev_ctxt,
359378 opaque,
360379 opaque_and_semitransparent,
@@ -388,12 +407,13 @@ impl SyntaxContext {
388407 } )
389408 }
390409
391- pub fn marks ( mut self ) -> Vec < Mark > {
410+ pub fn marks ( mut self ) -> Vec < ( Mark , Transparency ) > {
392411 HygieneData :: with ( |data| {
393412 let mut marks = Vec :: new ( ) ;
394413 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 ;
397417 }
398418 marks. reverse ( ) ;
399419 marks
0 commit comments