diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-06-24 19:54:23 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-06-30 01:53:32 +0300 |
| commit | 99ecdb3f5fc49efb3eccdd10fbe12dc98623a938 (patch) | |
| tree | 7c82e4221bf6f94e44ca58399c873b2b9eb29a25 /src/libsyntax_pos | |
| parent | 09856c85b73feff1db93990cd3d80f2c585b40c4 (diff) | |
| download | rust-99ecdb3f5fc49efb3eccdd10fbe12dc98623a938.tar.gz rust-99ecdb3f5fc49efb3eccdd10fbe12dc98623a938.zip | |
hygiene: Implement transparent marks
Diffstat (limited to 'src/libsyntax_pos')
| -rw-r--r-- | src/libsyntax_pos/hygiene.rs | 97 | ||||
| -rw-r--r-- | src/libsyntax_pos/lib.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax_pos/symbol.rs | 9 |
3 files changed, 90 insertions, 22 deletions
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 99d8b1b172d..e7f1f31084a 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -33,14 +33,17 @@ pub struct SyntaxContext(pub(super) u32); pub struct SyntaxContextData { pub outer_mark: Mark, pub prev_ctxt: SyntaxContext, - pub modern: SyntaxContext, + // This context, but with all transparent and semi-transparent marks filtered away. + pub opaque: SyntaxContext, + // This context, but with all transparent marks filtered away. + pub opaque_and_semitransparent: SyntaxContext, } /// A mark is a unique id associated with a macro expansion. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Mark(u32); -#[derive(Debug)] +#[derive(Clone, Debug)] struct MarkData { parent: Mark, transparency: Transparency, @@ -50,7 +53,7 @@ struct MarkData { /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)] pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. @@ -69,16 +72,26 @@ pub enum Transparency { } impl Mark { + fn fresh_with_data(mark_data: MarkData, data: &mut HygieneData) -> Self { + data.marks.push(mark_data); + Mark(data.marks.len() as u32 - 1) + } + pub fn fresh(parent: Mark) -> Self { HygieneData::with(|data| { - data.marks.push(MarkData { + Mark::fresh_with_data(MarkData { parent, // By default expansions behave like `macro_rules`. transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: None, - }); - Mark(data.marks.len() as u32 - 1) + }, data) + }) + } + + pub fn fresh_cloned(clone_from: Mark) -> Self { + HygieneData::with(|data| { + Mark::fresh_with_data(data.marks[clone_from.0 as usize].clone(), data) }) } @@ -207,7 +220,8 @@ impl HygieneData { syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), prev_ctxt: SyntaxContext(0), - modern: SyntaxContext(0), + opaque: SyntaxContext(0), + opaque_and_semitransparent: SyntaxContext(0), }], markings: HashMap::new(), default_edition: Edition::Edition2015, @@ -239,7 +253,7 @@ impl SyntaxContext { // Allocate a new SyntaxContext with the given ExpnInfo. This is used when // deserializing Spans from the incr. comp. cache. // FIXME(mw): This method does not restore MarkData::parent or - // SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things + // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things // don't seem to be used after HIR lowering, so everything should be fine // as long as incremental compilation does not kick in before that. pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { @@ -256,7 +270,8 @@ impl SyntaxContext { data.syntax_contexts.push(SyntaxContextData { outer_mark: mark, prev_ctxt: SyntaxContext::empty(), - modern: SyntaxContext::empty(), + opaque: SyntaxContext::empty(), + opaque_and_semitransparent: SyntaxContext::empty(), }); SyntaxContext(data.syntax_contexts.len() as u32 - 1) }) @@ -269,7 +284,13 @@ impl SyntaxContext { } let call_site_ctxt = - mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()).modern(); + mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()); + let call_site_ctxt = if mark.transparency() == Transparency::SemiTransparent { + call_site_ctxt.modern() + } else { + call_site_ctxt.modern_and_legacy() + }; + if call_site_ctxt == SyntaxContext::empty() { return self.apply_mark_internal(mark); } @@ -293,26 +314,53 @@ impl SyntaxContext { fn apply_mark_internal(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; - let mut modern = syntax_contexts[self.0 as usize].modern; - if data.marks[mark.0 as usize].transparency == Transparency::Opaque { - modern = *data.markings.entry((modern, mark)).or_insert_with(|| { - let len = syntax_contexts.len() as u32; + let transparency = data.marks[mark.0 as usize].transparency; + + let mut opaque = syntax_contexts[self.0 as usize].opaque; + let mut opaque_and_semitransparent = + syntax_contexts[self.0 as usize].opaque_and_semitransparent; + + if transparency >= Transparency::Opaque { + let prev_ctxt = opaque; + opaque = *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + let new_opaque = SyntaxContext(syntax_contexts.len() as u32); + syntax_contexts.push(SyntaxContextData { + outer_mark: mark, + prev_ctxt, + opaque: new_opaque, + opaque_and_semitransparent: new_opaque, + }); + new_opaque + }); + } + + if transparency >= Transparency::SemiTransparent { + let prev_ctxt = opaque_and_semitransparent; + opaque_and_semitransparent = + *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + let new_opaque_and_semitransparent = + SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, - prev_ctxt: modern, - modern: SyntaxContext(len), + prev_ctxt, + opaque, + opaque_and_semitransparent: new_opaque_and_semitransparent, }); - SyntaxContext(len) + new_opaque_and_semitransparent }); } - *data.markings.entry((self, mark)).or_insert_with(|| { + let prev_ctxt = self; + *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + let new_opaque_and_semitransparent_and_transparent = + SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, - prev_ctxt: self, - modern, + prev_ctxt, + opaque, + opaque_and_semitransparent, }); - SyntaxContext(syntax_contexts.len() as u32 - 1) + new_opaque_and_semitransparent_and_transparent }) }) } @@ -452,7 +500,12 @@ impl SyntaxContext { #[inline] pub fn modern(self) -> SyntaxContext { - HygieneData::with(|data| data.syntax_contexts[self.0 as usize].modern) + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].opaque) + } + + #[inline] + pub fn modern_and_legacy(self) -> SyntaxContext { + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].opaque_and_semitransparent) } #[inline] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 55dec31511c..308fb118f07 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -491,6 +491,12 @@ impl Span { let span = self.data(); span.with_ctxt(span.ctxt.modern()) } + + #[inline] + pub fn modern_and_legacy(self) -> Span { + let span = self.data(); + span.with_ctxt(span.ctxt.modern_and_legacy()) + } } #[derive(Clone, Debug)] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index bb64dad1208..fe0b479d161 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -68,6 +68,15 @@ impl Ident { Ident::new(self.name, self.span.modern()) } + // "Normalize" ident for use in comparisons using "local variable hygiene". + // Identifiers with same string value become same if they came from the same non-transparent + // macro (e.g. `macro` or `macro_rules!` items) and stay different if they came from different + // non-transparent macros. + // Technically, this operation strips all transparent marks from ident's syntactic context. + pub fn modern_and_legacy(self) -> Ident { + Ident::new(self.name, self.span.modern_and_legacy()) + } + pub fn gensym(self) -> Ident { Ident::new(self.name.gensymed(), self.span) } |
