Skip to content

Commit

Permalink
Rollup merge of rust-lang#50192 - bobtwinkles:libsyntax_extensions, r…
Browse files Browse the repository at this point in the history
…=jseyfried

Add some utilities to `libsyntax`

Adds a few functions to `Mark` and `Span` that I found useful in an upcoming refactor of NLL region error reporting. Also includes some new documentation based on my discussion with @jseyfried on IRC.

r? @jseyfried
  • Loading branch information
kennytm authored Apr 27, 2018
2 parents 8b36d9a + 73e0c1e commit 4a961d1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/libproc_macro/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl Span {
/// `self` was generated from, if any.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn parent(&self) -> Option<Span> {
self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site))
self.0.parent().map(Span)
}

/// The span for the origin source code that `self` was generated from. If
Expand Down
43 changes: 43 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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 la = least_ancestor(a, b);
/// assert!(a.is_descendant_of(la))
/// assert!(b.is_descendant_of(la))
/// ```
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::<Mark>();
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 {
Expand Down Expand Up @@ -238,6 +265,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;
Expand Down
6 changes: 6 additions & 0 deletions src/libsyntax_pos/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Span> {
self.ctxt().outer().expn_info().map(|i| i.call_site)
}

/// Return the source callee.
///
/// Returns None if the supplied span has no expansion trace,
Expand Down

0 comments on commit 4a961d1

Please sign in to comment.