diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-06-30 19:53:46 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-07-08 16:17:37 +0300 |
| commit | 94ef9f57f5fa985beb7588e5cb4c73f1b5f2dcba (patch) | |
| tree | 6fd06514639327df46c5a78a93f2a01008e3d6d5 /src/libsyntax_pos | |
| parent | 01b6d7cc6f1b1513b717bdc1bbc48f7407d4964c (diff) | |
| download | rust-94ef9f57f5fa985beb7588e5cb4c73f1b5f2dcba.tar.gz rust-94ef9f57f5fa985beb7588e5cb4c73f1b5f2dcba.zip | |
hygiene: Decouple transparencies from expansion IDs
Diffstat (limited to 'src/libsyntax_pos')
| -rw-r--r-- | src/libsyntax_pos/hygiene.rs | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ff23c2fb534..385174ea7fe 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -32,6 +32,7 @@ pub struct SyntaxContext(u32); #[derive(Copy, Clone, Debug)] struct SyntaxContextData { outer_mark: Mark, + transparency: Transparency, prev_ctxt: SyntaxContext, // This context, but with all transparent and semi-transparent marks filtered away. opaque: SyntaxContext, @@ -46,14 +47,14 @@ pub struct Mark(u32); #[derive(Clone, Debug)] struct MarkData { parent: Mark, - transparency: Transparency, + default_transparency: Transparency, is_builtin: bool, expn_info: Option<ExpnInfo>, } /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, 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. @@ -81,7 +82,7 @@ impl Mark { Mark::fresh_with_data(MarkData { parent, // By default expansions behave like `macro_rules`. - transparency: Transparency::SemiTransparent, + default_transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: None, }, data) @@ -127,9 +128,11 @@ impl Mark { }) } + // FIXME: This operation doesn't really make sense when single macro expansion + // can produce tokens with different transparencies. Figure out how to avoid it. pub fn modern(mut self) -> Mark { HygieneData::with(|data| { - while data.marks[self.0 as usize].transparency != Transparency::Opaque { + while data.marks[self.0 as usize].default_transparency != Transparency::Opaque { self = data.marks[self.0 as usize].parent; } self @@ -137,24 +140,20 @@ impl Mark { } #[inline] - pub fn transparency(self) -> Transparency { - assert_ne!(self, Mark::root()); - HygieneData::with(|data| data.marks[self.0 as usize].transparency) - } - - #[inline] - pub fn set_transparency(self, transparency: Transparency) { + pub fn set_default_transparency(self, transparency: Transparency) { assert_ne!(self, Mark::root()); - HygieneData::with(|data| data.marks[self.0 as usize].transparency = transparency) + HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency) } #[inline] pub fn is_builtin(self) -> bool { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].is_builtin) } #[inline] pub fn set_is_builtin(self, is_builtin: bool) { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin) } @@ -201,7 +200,7 @@ impl Mark { crate struct HygieneData { marks: Vec<MarkData>, syntax_contexts: Vec<SyntaxContextData>, - markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, + markings: HashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>, default_edition: Edition, } @@ -212,12 +211,13 @@ impl HygieneData { parent: Mark::root(), // If the root is opaque, then loops searching for an opaque mark // will automatically stop after reaching it. - transparency: Transparency::Opaque, + default_transparency: Transparency::Opaque, is_builtin: true, expn_info: None, }], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), + transparency: Transparency::Opaque, prev_ctxt: SyntaxContext(0), opaque: SyntaxContext(0), opaque_and_semitransparent: SyntaxContext(0), @@ -267,7 +267,7 @@ impl SyntaxContext { HygieneData::with(|data| { data.marks.push(MarkData { parent: Mark::root(), - transparency: Transparency::SemiTransparent, + default_transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: Some(expansion_info), }); @@ -276,6 +276,7 @@ impl SyntaxContext { data.syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency: Transparency::SemiTransparent, prev_ctxt: SyntaxContext::empty(), opaque: SyntaxContext::empty(), opaque_and_semitransparent: SyntaxContext::empty(), @@ -284,22 +285,31 @@ impl SyntaxContext { }) } - /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { - if mark.transparency() == Transparency::Opaque { - return self.apply_mark_internal(mark); + assert_ne!(mark, Mark::root()); + self.apply_mark_with_transparency( + mark, HygieneData::with(|data| data.marks[mark.0 as usize].default_transparency) + ) + } + + /// Extend a syntax context with a given mark and transparency + pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency) + -> SyntaxContext { + assert_ne!(mark, Mark::root()); + if transparency == Transparency::Opaque { + return self.apply_mark_internal(mark, transparency); } let call_site_ctxt = mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()); - let call_site_ctxt = if mark.transparency() == Transparency::SemiTransparent { + let call_site_ctxt = if 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); + return self.apply_mark_internal(mark, transparency); } // Otherwise, `mark` is a macros 1.0 definition and the call site is in a @@ -312,27 +322,26 @@ impl SyntaxContext { // // See the example at `test/run-pass/hygiene/legacy_interaction.rs`. let mut ctxt = call_site_ctxt; - for mark in self.marks() { - ctxt = ctxt.apply_mark_internal(mark); + for (mark, transparency) in self.marks() { + ctxt = ctxt.apply_mark_internal(mark, transparency); } - ctxt.apply_mark_internal(mark) + ctxt.apply_mark_internal(mark, transparency) } - fn apply_mark_internal(self, mark: Mark) -> SyntaxContext { + fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; - 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(|| { + opaque = *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque: new_opaque, opaque_and_semitransparent: new_opaque, @@ -344,11 +353,12 @@ impl SyntaxContext { if transparency >= Transparency::SemiTransparent { let prev_ctxt = opaque_and_semitransparent; opaque_and_semitransparent = - *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque_and_semitransparent = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque, opaque_and_semitransparent: new_opaque_and_semitransparent, @@ -358,11 +368,12 @@ impl SyntaxContext { } let prev_ctxt = self; - *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque_and_semitransparent_and_transparent = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque, opaque_and_semitransparent, @@ -396,12 +407,13 @@ impl SyntaxContext { }) } - pub fn marks(mut self) -> Vec<Mark> { + pub fn marks(mut self) -> Vec<(Mark, Transparency)> { HygieneData::with(|data| { let mut marks = Vec::new(); while self != SyntaxContext::empty() { - marks.push(data.syntax_contexts[self.0 as usize].outer_mark); - self = data.syntax_contexts[self.0 as usize].prev_ctxt; + let ctxt_data = &data.syntax_contexts[self.0 as usize]; + marks.push((ctxt_data.outer_mark, ctxt_data.transparency)); + self = ctxt_data.prev_ctxt; } marks.reverse(); marks |
