From d2dc21df02a6f24b0c5629d3c3ebc7c9b85d20da Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Sat, 21 Apr 2018 18:00:09 -0400 Subject: [PATCH 1/4] Add documentation for SyntaxContext::remove_mark --- src/libsyntax_pos/hygiene.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 5e96b5ce6733c..6eb662744c302 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -238,6 +238,22 @@ impl SyntaxContext { }) } + /// Pulls a single mark off of the syntax context. This effectively moves the + /// context up one macro definition level. That is, if we have a nested macro + /// definition as follows: + /// + /// ```rust + /// macro_rules! f { + /// macro_rules! g { + /// ... + /// } + /// } + /// ``` + /// + /// and we have a SyntaxContext that is referring to something declared by an invocation + /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the + /// invocation of f that created g1. + /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> Mark { HygieneData::with(|data| { let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark; From 263b36b071ba8b52cd4f79ca36494b05d4762430 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Sat, 21 Apr 2018 18:15:54 -0400 Subject: [PATCH 2/4] Implement parent() on `syntax_pos::Span` ... and reimplement proc_macro::Span::parent using it. This function turns out to be useful in the compiler as well --- src/libproc_macro/lib.rs | 2 +- src/libsyntax_pos/lib.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index e171216523a1e..4d24353a383d1 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -270,7 +270,7 @@ impl Span { /// `self` was generated from, if any. #[unstable(feature = "proc_macro", issue = "38356")] pub fn parent(&self) -> Option { - self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site)) + self.0.parent().map(|x| { Span(x) }) } /// The span for the origin source code that `self` was generated from. If diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9a7d1fd8ee6cb..19f52d83a0176 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -291,6 +291,12 @@ impl Span { self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) } + /// The `Span for the tokens in the previous macro expansion from which `self` was generated, + /// if any + pub fn parent(self) -> Option { + self.ctxt().outer().expn_info().map(|i| i.call_site) + } + /// Return the source callee. /// /// Returns None if the supplied span has no expansion trace, From 498dbe44537998bd4bba6c28232a22e9243b9c67 Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Sat, 21 Apr 2018 18:20:17 -0400 Subject: [PATCH 3/4] Implement a least upper bound for marks. This is useful when trying to compute when something is lexically before something else, but they aren't necessarily in the same SyntaxContext --- src/libsyntax_pos/hygiene.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 6eb662744c302..8e9564d0ac191 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -21,6 +21,7 @@ use symbol::{Ident, Symbol}; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::collections::HashMap; +use rustc_data_structures::fx::FxHashSet; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). @@ -117,6 +118,32 @@ impl Mark { true }) } + + /// Computes a mark such that both input marks are descendants of (or equal to) the returned + /// mark. That is, the following holds: + /// + /// ```rust + /// let lub = lub(a, b); + /// assert!(a.is_descendant_of(lub)) + /// assert!(b.is_descendant_of(lub)) + /// ``` + pub fn lub(mut a: Mark, mut b: Mark) -> Mark { + HygieneData::with(|data| { + // Compute the path from a to the root + let mut a_path = FxHashSet::(); + while a != Mark::root() { + a_path.insert(a); + a = data.marks[a.0 as usize].parent; + } + + // While the path from b to the root hasn't intersected, move up the tree + while !a_path.contains(&b) { + b = data.marks[b.0 as usize].parent; + } + + b + }) + } } pub struct HygieneData { From 73e0c1e968caaf7b70d659e58c0a40782c60f8da Mon Sep 17 00:00:00 2001 From: bobtwinkles Date: Thu, 26 Apr 2018 18:28:34 -0400 Subject: [PATCH 4/4] Fix review nits --- src/libproc_macro/lib.rs | 2 +- src/libsyntax_pos/hygiene.rs | 10 +++++----- src/libsyntax_pos/lib.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 4d24353a383d1..f51dbc3772f06 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -270,7 +270,7 @@ impl Span { /// `self` was generated from, if any. #[unstable(feature = "proc_macro", issue = "38356")] pub fn parent(&self) -> Option { - self.0.parent().map(|x| { Span(x) }) + self.0.parent().map(Span) } /// The span for the origin source code that `self` was generated from. If diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 8e9564d0ac191..658408519b9c7 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -123,11 +123,11 @@ impl Mark { /// mark. That is, the following holds: /// /// ```rust - /// let lub = lub(a, b); - /// assert!(a.is_descendant_of(lub)) - /// assert!(b.is_descendant_of(lub)) + /// let la = least_ancestor(a, b); + /// assert!(a.is_descendant_of(la)) + /// assert!(b.is_descendant_of(la)) /// ``` - pub fn lub(mut a: Mark, mut b: Mark) -> Mark { + pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark { HygieneData::with(|data| { // Compute the path from a to the root let mut a_path = FxHashSet::(); @@ -138,7 +138,7 @@ impl Mark { // While the path from b to the root hasn't intersected, move up the tree while !a_path.contains(&b) { - b = data.marks[b.0 as usize].parent; + b = data.marks[b.0 as usize].parent; } b diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 19f52d83a0176..8d37b4aa3968f 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -291,7 +291,7 @@ impl Span { self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) } - /// The `Span for the tokens in the previous macro expansion from which `self` was generated, + /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any pub fn parent(self) -> Option { self.ctxt().outer().expn_info().map(|i| i.call_site)