Improve interaction between macros 2.0 and macro_rules!.

This commit is contained in:
Jeffrey Seyfried 2017-11-29 01:05:31 -08:00
parent 3dfbc88a62
commit d052d28d70
8 changed files with 126 additions and 9 deletions

View file

@ -181,6 +181,33 @@ impl SyntaxContext {
/// Extend a syntax context with a given mark
pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
if mark.kind() == MarkKind::Modern {
return self.apply_mark_internal(mark);
}
let call_site_ctxt =
mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()).modern();
if call_site_ctxt == SyntaxContext::empty() {
return self.apply_mark_internal(mark);
}
// Otherwise, `mark` is a macros 1.0 definition and the call site is in a
// macros 2.0 expansion, i.e. a macros 1.0 invocation is in a macros 2.0 definition.
//
// In this case, the tokens from the macros 1.0 definition inherit the hygiene
// at their invocation. That is, we pretend that the macros 1.0 definition
// was defined at its invocation (i.e. inside the macros 2.0 definition)
// so that the macros 2.0 definition remains hygienic.
//
// 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);
}
ctxt.apply_mark_internal(mark)
}
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;
@ -215,6 +242,18 @@ impl SyntaxContext {
})
}
pub fn marks(mut self) -> Vec<Mark> {
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;
}
marks.reverse();
marks
})
}
/// Adjust this context for resolution in a scope created by the given expansion.
/// For example, consider the following three resolutions of `f`:
/// ```rust