Add support for undetermined macro invocations.
This commit is contained in:
parent
d5281ef681
commit
31e0e12e69
@ -17,7 +17,7 @@ use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
|
||||
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
|
||||
use syntax::ext::base::{NormalTT, SyntaxExtension};
|
||||
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
@ -173,7 +173,8 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
|
||||
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, _force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
let (name, span) = match invoc.kind {
|
||||
InvocationKind::Bang { ref mac, .. } => {
|
||||
let path = &mac.node.path;
|
||||
@ -181,7 +182,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
!path.segments[0].parameters.is_empty() {
|
||||
self.session.span_err(path.span,
|
||||
"expected macro name without module separators");
|
||||
return None;
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
(path.segments[0].identifier.name, path.span)
|
||||
}
|
||||
@ -192,12 +193,12 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
|
||||
invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
|
||||
}
|
||||
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).or_else(|| {
|
||||
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
|
||||
let mut err =
|
||||
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
|
||||
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||
err.emit();
|
||||
None
|
||||
Determinacy::Determined
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use self::Determinacy::*;
|
||||
use self::ImportDirectiveSubclass::*;
|
||||
|
||||
use Module;
|
||||
@ -26,6 +25,7 @@ use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
|
||||
use rustc::hir::def::*;
|
||||
|
||||
use syntax::ast::{NodeId, Name};
|
||||
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::Span;
|
||||
|
||||
@ -37,12 +37,6 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Determinacy {
|
||||
Determined,
|
||||
Undetermined,
|
||||
}
|
||||
|
||||
/// Contains data for specific types of import directives.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImportDirectiveSubclass<'a> {
|
||||
|
@ -522,10 +522,17 @@ pub trait Resolver {
|
||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
||||
|
||||
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
|
||||
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
|
||||
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Determinacy {
|
||||
Determined,
|
||||
Undetermined,
|
||||
}
|
||||
|
||||
pub struct DummyResolver;
|
||||
|
||||
impl Resolver for DummyResolver {
|
||||
@ -539,8 +546,9 @@ impl Resolver for DummyResolver {
|
||||
|
||||
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
|
||||
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
|
||||
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
|
||||
None
|
||||
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,13 +225,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
invocations.reverse();
|
||||
|
||||
let mut expansions = Vec::new();
|
||||
while let Some(invoc) = invocations.pop() {
|
||||
let mut undetermined_invocations = Vec::new();
|
||||
let (mut progress, mut force) = (false, !self.monotonic);
|
||||
loop {
|
||||
let invoc = if let Some(invoc) = invocations.pop() {
|
||||
invoc
|
||||
} else if undetermined_invocations.is_empty() {
|
||||
break
|
||||
} else {
|
||||
invocations = mem::replace(&mut undetermined_invocations, Vec::new());
|
||||
force = !mem::replace(&mut progress, false);
|
||||
continue
|
||||
};
|
||||
|
||||
let scope =
|
||||
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
|
||||
let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
|
||||
Ok(ext) => Some(ext),
|
||||
Err(Determinacy::Determined) => None,
|
||||
Err(Determinacy::Undetermined) => {
|
||||
undetermined_invocations.push(invoc);
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
progress = true;
|
||||
let ExpansionData { depth, mark, .. } = invoc.expansion_data;
|
||||
self.cx.current_expansion = invoc.expansion_data.clone();
|
||||
|
||||
let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
|
||||
self.cx.current_expansion.mark = scope;
|
||||
let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
|
||||
let expansion = match ext {
|
||||
Some(ext) => self.expand_invoc(invoc, ext),
|
||||
None => invoc.expansion_kind.dummy(invoc.span()),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user