Add feature use_extern_macros
.
This commit is contained in:
parent
b25c063caa
commit
9c88650080
6 changed files with 243 additions and 140 deletions
|
@ -504,9 +504,11 @@ impl<'b> Resolver<'b> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
|
||||
let def_id = match def {
|
||||
Def::Macro(def_id) => def_id,
|
||||
pub fn get_macro(&mut self, binding: &'b NameBinding<'b>) -> Rc<SyntaxExtension> {
|
||||
let def_id = match binding.kind {
|
||||
NameBindingKind::Def(Def::Macro(def_id)) => def_id,
|
||||
NameBindingKind::Import { binding, .. } => return self.get_macro(binding),
|
||||
NameBindingKind::Ambiguity { b1, .. } => return self.get_macro(b1),
|
||||
_ => panic!("Expected Def::Macro(..)"),
|
||||
};
|
||||
if let Some(ext) = self.macro_map.get(&def_id) {
|
||||
|
@ -579,7 +581,7 @@ impl<'b> Resolver<'b> {
|
|||
});
|
||||
} else {
|
||||
for (name, span) in legacy_imports.imports {
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None);
|
||||
if let Success(binding) = result {
|
||||
self.legacy_import_macro(name, binding, span, allow_shadowing);
|
||||
} else {
|
||||
|
@ -589,7 +591,7 @@ impl<'b> Resolver<'b> {
|
|||
}
|
||||
for (name, span) in legacy_imports.reexports {
|
||||
self.used_crates.insert(module.def_id().unwrap().krate);
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
|
||||
let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None);
|
||||
if let Success(binding) = result {
|
||||
self.macro_exports.push(Export { name: name, def: binding.def() });
|
||||
} else {
|
||||
|
|
|
@ -540,6 +540,7 @@ pub enum Namespace {
|
|||
pub struct PerNS<T> {
|
||||
value_ns: T,
|
||||
type_ns: T,
|
||||
macro_ns: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
|
||||
|
@ -548,7 +549,7 @@ impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
|
|||
match ns {
|
||||
ValueNS => &self.value_ns,
|
||||
TypeNS => &self.type_ns,
|
||||
MacroNS => unreachable!(),
|
||||
MacroNS => self.macro_ns.as_ref().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -558,7 +559,7 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
|
|||
match ns {
|
||||
ValueNS => &mut self.value_ns,
|
||||
TypeNS => &mut self.type_ns,
|
||||
MacroNS => unreachable!(),
|
||||
MacroNS => self.macro_ns.as_mut().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -675,7 +676,7 @@ impl<'a> Visitor for Resolver<'a> {
|
|||
|
||||
pub type ErrorMessage = Option<(Span, String)>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ResolveResult<T> {
|
||||
Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
|
||||
Indeterminate, // Couldn't determine due to unresolved globs.
|
||||
|
@ -683,14 +684,6 @@ pub enum ResolveResult<T> {
|
|||
}
|
||||
|
||||
impl<T> ResolveResult<T> {
|
||||
fn and_then<U, F: FnOnce(T) -> ResolveResult<U>>(self, f: F) -> ResolveResult<U> {
|
||||
match self {
|
||||
Failed(msg) => Failed(msg),
|
||||
Indeterminate => Indeterminate,
|
||||
Success(t) => f(t),
|
||||
}
|
||||
}
|
||||
|
||||
fn success(self) -> Option<T> {
|
||||
match self {
|
||||
Success(t) => Some(t),
|
||||
|
@ -825,6 +818,7 @@ pub struct ModuleS<'a> {
|
|||
normal_ancestor_id: Option<NodeId>,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Mark, Name, Span)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
unresolved_invocations: RefCell<FxHashSet<Mark>>,
|
||||
|
@ -852,6 +846,7 @@ impl<'a> ModuleS<'a> {
|
|||
kind: kind,
|
||||
normal_ancestor_id: None,
|
||||
resolutions: RefCell::new(FxHashMap()),
|
||||
legacy_macro_resolutions: RefCell::new(Vec::new()),
|
||||
unresolved_invocations: RefCell::new(FxHashSet()),
|
||||
no_implicit_prelude: false,
|
||||
glob_importers: RefCell::new(Vec::new()),
|
||||
|
@ -943,6 +938,7 @@ struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
|
|||
struct AmbiguityError<'a> {
|
||||
span: Span,
|
||||
name: Name,
|
||||
lexical: bool,
|
||||
b1: &'a NameBinding<'a>,
|
||||
b2: &'a NameBinding<'a>,
|
||||
}
|
||||
|
@ -1001,7 +997,7 @@ impl<'a> NameBinding<'a> {
|
|||
fn is_glob_import(&self) -> bool {
|
||||
match self.kind {
|
||||
NameBindingKind::Import { directive, .. } => directive.is_glob(),
|
||||
NameBindingKind::Ambiguity { .. } => true,
|
||||
NameBindingKind::Ambiguity { b1, .. } => b1.is_glob_import(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -1136,6 +1132,7 @@ pub struct Resolver<'a> {
|
|||
arenas: &'a ResolverArenas<'a>,
|
||||
dummy_binding: &'a NameBinding<'a>,
|
||||
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
|
||||
use_extern_macros: bool, // true if `#![feature(use_extern_macros)]`
|
||||
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
crate_loader: &'a mut CrateLoader,
|
||||
|
@ -1300,6 +1297,7 @@ impl<'a> Resolver<'a> {
|
|||
ribs: PerNS {
|
||||
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
macro_ns: None,
|
||||
},
|
||||
label_ribs: Vec::new(),
|
||||
|
||||
|
@ -1336,6 +1334,7 @@ impl<'a> Resolver<'a> {
|
|||
vis: ty::Visibility::Public,
|
||||
}),
|
||||
new_import_semantics: session.features.borrow().item_like_imports,
|
||||
use_extern_macros: session.features.borrow().use_extern_macros,
|
||||
|
||||
exported_macros: Vec::new(),
|
||||
crate_loader: crate_loader,
|
||||
|
@ -1365,6 +1364,10 @@ impl<'a> Resolver<'a> {
|
|||
PerNS {
|
||||
type_ns: f(self, TypeNS),
|
||||
value_ns: f(self, ValueNS),
|
||||
macro_ns: match self.use_extern_macros {
|
||||
true => Some(f(self, MacroNS)),
|
||||
false => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1403,8 +1406,9 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
NameBindingKind::Import { .. } => false,
|
||||
NameBindingKind::Ambiguity { b1, b2 } => {
|
||||
let ambiguity_error = AmbiguityError { span: span, name: name, b1: b1, b2: b2 };
|
||||
self.ambiguity_errors.push(ambiguity_error);
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
span: span, name: name, lexical: false, b1: b1, b2: b2,
|
||||
});
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
|
@ -1438,7 +1442,7 @@ impl<'a> Resolver<'a> {
|
|||
-> ResolveResult<Module<'a>> {
|
||||
fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>)
|
||||
-> Option<Module<'a>> {
|
||||
match this.resolve_name_in_module(module, needle, TypeNS, false, None) {
|
||||
match this.resolve_name_in_module(module, needle, TypeNS, false, false, None) {
|
||||
Success(binding) if binding.is_extern_crate() => Some(module),
|
||||
_ => if let (&ModuleKind::Def(..), Some(parent)) = (&module.kind, module.parent) {
|
||||
search_parent_externals(this, needle, parent)
|
||||
|
@ -1456,7 +1460,7 @@ impl<'a> Resolver<'a> {
|
|||
// modules as we go.
|
||||
while index < module_path_len {
|
||||
let name = module_path[index].name;
|
||||
match self.resolve_name_in_module(search_module, name, TypeNS, false, span) {
|
||||
match self.resolve_name_in_module(search_module, name, TypeNS, false, false, span) {
|
||||
Failed(_) => {
|
||||
let segment_name = name.as_str();
|
||||
let module_name = module_to_string(search_module);
|
||||
|
@ -1613,7 +1617,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
if let ModuleRibKind(module) = self.ribs[ns][i].kind {
|
||||
let name = ident.name;
|
||||
let item = self.resolve_name_in_module(module, name, ns, true, record_used);
|
||||
let item = self.resolve_name_in_module(module, name, ns, true, false, record_used);
|
||||
if let Success(binding) = item {
|
||||
// The ident resolves to an item.
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
|
@ -1622,7 +1626,7 @@ impl<'a> Resolver<'a> {
|
|||
if let ModuleKind::Block(..) = module.kind { // We can see through blocks
|
||||
} else if !module.no_implicit_prelude {
|
||||
return self.prelude.and_then(|prelude| {
|
||||
self.resolve_name_in_module(prelude, name, ns, false, None).success()
|
||||
self.resolve_name_in_module(prelude, name, ns, false, false, None).success()
|
||||
}).map(LexicalScopeBinding::Item)
|
||||
} else {
|
||||
return None;
|
||||
|
@ -1717,6 +1721,7 @@ impl<'a> Resolver<'a> {
|
|||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
|
||||
|
||||
self.finalize_current_module_macro_resolutions();
|
||||
f(self);
|
||||
|
||||
self.current_module = orig_module;
|
||||
|
@ -2221,6 +2226,7 @@ impl<'a> Resolver<'a> {
|
|||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.current_module = anonymous_module;
|
||||
self.finalize_current_module_macro_resolutions();
|
||||
} else {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
}
|
||||
|
@ -2754,8 +2760,7 @@ impl<'a> Resolver<'a> {
|
|||
let module_path =
|
||||
segments.split_last().unwrap().1.iter().map(|ps| ps.identifier).collect::<Vec<_>>();
|
||||
|
||||
let containing_module;
|
||||
match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) {
|
||||
let module = match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) {
|
||||
Failed(err) => {
|
||||
if let Some((span, msg)) = err {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
|
@ -2763,14 +2768,11 @@ impl<'a> Resolver<'a> {
|
|||
return Err(true);
|
||||
}
|
||||
Indeterminate => return Err(false),
|
||||
Success(resulting_module) => {
|
||||
containing_module = resulting_module;
|
||||
}
|
||||
}
|
||||
Success(module) => module,
|
||||
};
|
||||
|
||||
let name = segments.last().unwrap().identifier.name;
|
||||
let result =
|
||||
self.resolve_name_in_module(containing_module, name, namespace, false, Some(span));
|
||||
let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span));
|
||||
result.success().ok_or(false)
|
||||
}
|
||||
|
||||
|
@ -2782,10 +2784,9 @@ impl<'a> Resolver<'a> {
|
|||
where T: Named,
|
||||
{
|
||||
let module_path = segments.split_last().unwrap().1.iter().map(T::ident).collect::<Vec<_>>();
|
||||
let root_module = self.graph_root;
|
||||
let root = self.graph_root;
|
||||
|
||||
let containing_module;
|
||||
match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) {
|
||||
let module = match self.resolve_module_path_from_root(root, &module_path, 0, Some(span)) {
|
||||
Failed(err) => {
|
||||
if let Some((span, msg)) = err {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
|
@ -2795,14 +2796,11 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
Indeterminate => return Err(false),
|
||||
|
||||
Success(resulting_module) => {
|
||||
containing_module = resulting_module;
|
||||
}
|
||||
}
|
||||
Success(module) => module,
|
||||
};
|
||||
|
||||
let name = segments.last().unwrap().ident().name;
|
||||
let result =
|
||||
self.resolve_name_in_module(containing_module, name, namespace, false, Some(span));
|
||||
let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span));
|
||||
result.success().ok_or(false)
|
||||
}
|
||||
|
||||
|
@ -3383,14 +3381,18 @@ impl<'a> Resolver<'a> {
|
|||
self.report_shadowing_errors();
|
||||
let mut reported_spans = FxHashSet();
|
||||
|
||||
for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
|
||||
for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
|
||||
if !reported_spans.insert(span) { continue }
|
||||
let msg1 = format!("`{}` could resolve to the name imported here", name);
|
||||
let msg2 = format!("`{}` could also resolve to the name imported here", name);
|
||||
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
|
||||
.span_note(b1.span, &msg1)
|
||||
.span_note(b2.span, &msg2)
|
||||
.note(&format!("Consider adding an explicit import of `{}` to disambiguate", name))
|
||||
.note(&if lexical || !b1.is_glob_import() {
|
||||
"macro-expanded macro imports do not shadow".to_owned()
|
||||
} else {
|
||||
format!("consider adding an explicit import of `{}` to disambiguate", name)
|
||||
})
|
||||
.emit();
|
||||
}
|
||||
|
||||
|
@ -3413,12 +3415,12 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
fn report_shadowing_errors(&mut self) {
|
||||
for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) {
|
||||
self.resolve_macro_name(scope, name);
|
||||
self.resolve_legacy_scope(scope, name, true);
|
||||
}
|
||||
|
||||
let mut reported_errors = FxHashSet();
|
||||
for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
|
||||
if self.resolve_macro_name(binding.parent, binding.name).is_some() &&
|
||||
if self.resolve_legacy_scope(binding.parent, binding.name, false).is_some() &&
|
||||
reported_errors.insert((binding.name, binding.span)) {
|
||||
let msg = format!("`{}` is already in scope", binding.name);
|
||||
self.session.struct_span_err(binding.span, &msg)
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver};
|
||||
use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver, AmbiguityError};
|
||||
use Namespace::{self, MacroNS};
|
||||
use ResolveResult::{Success, Indeterminate, Failed};
|
||||
use build_reduced_graph::BuildReducedGraphVisitor;
|
||||
use resolve_imports::ImportResolver;
|
||||
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
|
||||
|
@ -17,7 +19,7 @@ use rustc::hir::map::{self, DefCollector};
|
|||
use rustc::ty;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{NormalTT, SyntaxExtension};
|
||||
|
@ -85,6 +87,11 @@ pub struct LegacyBinding<'a> {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
pub enum MacroBinding<'a> {
|
||||
Legacy(&'a LegacyBinding<'a>),
|
||||
Modern(&'a NameBinding<'a>),
|
||||
}
|
||||
|
||||
impl<'a> base::Resolver for Resolver<'a> {
|
||||
fn next_node_id(&mut self) -> ast::NodeId {
|
||||
self.session.next_node_id()
|
||||
|
@ -140,6 +147,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
expansion: mark,
|
||||
};
|
||||
expansion.visit_with(&mut visitor);
|
||||
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
|
||||
invocation.expansion.set(visitor.legacy_scope);
|
||||
}
|
||||
|
||||
|
@ -201,7 +209,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
for i in 0..attrs.len() {
|
||||
let name = intern(&attrs[i].name());
|
||||
match self.builtin_macros.get(&name).cloned() {
|
||||
Some(binding) => match *self.get_macro(binding.def()) {
|
||||
Some(binding) => match *self.get_macro(binding) {
|
||||
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
|
||||
return Some(attrs.remove(i))
|
||||
}
|
||||
|
@ -225,25 +233,77 @@ 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).ok_or_else(|| {
|
||||
if force {
|
||||
let msg = format!("macro undefined: '{}!'", name);
|
||||
let mut err = self.session.struct_span_err(path.span, &msg);
|
||||
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||
err.emit();
|
||||
Determinacy::Determined
|
||||
} else {
|
||||
Determinacy::Undetermined
|
||||
}
|
||||
})
|
||||
|
||||
self.current_module = invocation.module.get();
|
||||
let result = match self.resolve_legacy_scope(invocation.legacy_scope.get(), name, false) {
|
||||
Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()),
|
||||
Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)),
|
||||
None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) {
|
||||
Some(binding) => Ok(self.get_macro(binding)),
|
||||
None => return Err(if force {
|
||||
let msg = format!("macro undefined: '{}!'", name);
|
||||
let mut err = self.session.struct_span_err(path.span, &msg);
|
||||
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||
err.emit();
|
||||
Determinacy::Determined
|
||||
} else {
|
||||
Determinacy::Undetermined
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
if self.use_extern_macros {
|
||||
self.current_module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((scope, name, path.span));
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
pub fn resolve_macro_name(&mut self, mut scope: LegacyScope<'a>, name: ast::Name)
|
||||
-> Option<Rc<SyntaxExtension>> {
|
||||
// Resolve the name in the module's lexical scope, excluding non-items.
|
||||
fn resolve_in_item_lexical_scope(
|
||||
&mut self, name: Name, ns: Namespace, record_used: Option<Span>,
|
||||
) -> Option<&'a NameBinding<'a>> {
|
||||
let mut module = self.current_module;
|
||||
let mut potential_expanded_shadower = None;
|
||||
loop {
|
||||
// Since expanded macros may not shadow the lexical scope (enforced below),
|
||||
// we can ignore unresolved invocations (indicated by the penultimate argument).
|
||||
match self.resolve_name_in_module(module, name, ns, true, true, record_used) {
|
||||
Success(binding) => {
|
||||
let span = match record_used {
|
||||
Some(span) => span,
|
||||
None => return Some(binding),
|
||||
};
|
||||
if let Some(shadower) = potential_expanded_shadower {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
span: span, name: name, b1: shadower, b2: binding, lexical: true,
|
||||
});
|
||||
return Some(shadower);
|
||||
} else if binding.expansion == Mark::root() {
|
||||
return Some(binding);
|
||||
} else {
|
||||
potential_expanded_shadower = Some(binding);
|
||||
}
|
||||
},
|
||||
Indeterminate => return None,
|
||||
Failed(..) => {}
|
||||
}
|
||||
|
||||
match module.kind {
|
||||
ModuleKind::Block(..) => module = module.parent.unwrap(),
|
||||
ModuleKind::Def(..) => return potential_expanded_shadower,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_legacy_scope(
|
||||
&mut self, mut scope: LegacyScope<'a>, name: ast::Name, record_used: bool,
|
||||
) -> Option<MacroBinding<'a>> {
|
||||
let mut possible_time_travel = None;
|
||||
let mut relative_depth: u32 = 0;
|
||||
let mut binding = None;
|
||||
loop {
|
||||
scope = match scope {
|
||||
LegacyScope::Empty => break,
|
||||
|
@ -262,25 +322,59 @@ impl<'a> Resolver<'a> {
|
|||
relative_depth = relative_depth.saturating_sub(1);
|
||||
invocation.legacy_scope.get()
|
||||
}
|
||||
LegacyScope::Binding(binding) => {
|
||||
if binding.name == name {
|
||||
if let Some(scope) = possible_time_travel {
|
||||
// Check for disallowed shadowing later
|
||||
self.lexical_macro_resolutions.push((name, scope));
|
||||
} else if relative_depth > 0 {
|
||||
self.disallowed_shadowing.push(binding);
|
||||
LegacyScope::Binding(potential_binding) => {
|
||||
if potential_binding.name == name {
|
||||
if (!self.use_extern_macros || record_used) && relative_depth > 0 {
|
||||
self.disallowed_shadowing.push(potential_binding);
|
||||
}
|
||||
return Some(binding.ext.clone());
|
||||
binding = Some(potential_binding);
|
||||
break
|
||||
}
|
||||
binding.parent
|
||||
potential_binding.parent
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(scope) = possible_time_travel {
|
||||
self.lexical_macro_resolutions.push((name, scope));
|
||||
let binding = match binding {
|
||||
Some(binding) => MacroBinding::Legacy(binding),
|
||||
None => match self.builtin_macros.get(&name).cloned() {
|
||||
Some(binding) => MacroBinding::Modern(binding),
|
||||
None => return None,
|
||||
},
|
||||
};
|
||||
|
||||
if !self.use_extern_macros {
|
||||
if let Some(scope) = possible_time_travel {
|
||||
// Check for disallowed shadowing later
|
||||
self.lexical_macro_resolutions.push((name, scope));
|
||||
}
|
||||
}
|
||||
|
||||
Some(binding)
|
||||
}
|
||||
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
let module = self.current_module;
|
||||
for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() {
|
||||
let legacy_scope = self.invocations[&mark].legacy_scope.get();
|
||||
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true);
|
||||
let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span));
|
||||
let (legacy_resolution, resolution) = match (legacy_resolution, resolution) {
|
||||
(Some(legacy_resolution), Some(resolution)) => (legacy_resolution, resolution),
|
||||
_ => continue,
|
||||
};
|
||||
let (legacy_span, participle) = match legacy_resolution {
|
||||
MacroBinding::Modern(binding) if binding.def() == resolution.def() => continue,
|
||||
MacroBinding::Modern(binding) => (binding.span, "imported"),
|
||||
MacroBinding::Legacy(binding) => (binding.span, "defined"),
|
||||
};
|
||||
let msg1 = format!("`{}` could resolve to the macro {} here", name, participle);
|
||||
let msg2 = format!("`{}` could also resolve to the macro imported here", name);
|
||||
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
|
||||
.span_note(legacy_span, &msg1)
|
||||
.span_note(resolution.span, &msg2)
|
||||
.emit();
|
||||
}
|
||||
self.builtin_macros.get(&name).cloned().map(|binding| self.get_macro(binding.def()))
|
||||
}
|
||||
|
||||
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
use self::ImportDirectiveSubclass::*;
|
||||
|
||||
use {Module, PerNS};
|
||||
use Namespace::{self, TypeNS};
|
||||
use Namespace::{self, TypeNS, MacroNS};
|
||||
use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding};
|
||||
use ResolveResult;
|
||||
use ResolveResult::*;
|
||||
|
@ -142,6 +142,7 @@ impl<'a> Resolver<'a> {
|
|||
name: Name,
|
||||
ns: Namespace,
|
||||
allow_private_imports: bool,
|
||||
ignore_unresolved_invocations: bool,
|
||||
record_used: Option<Span>)
|
||||
-> ResolveResult<&'a NameBinding<'a>> {
|
||||
self.populate_module_if_necessary(module);
|
||||
|
@ -175,23 +176,55 @@ impl<'a> Resolver<'a> {
|
|||
return resolution.binding.map(Success).unwrap_or(Failed(None));
|
||||
}
|
||||
|
||||
// If the resolution doesn't depend on glob definability, check privacy and return.
|
||||
if let Some(result) = self.try_result(&resolution, module, ns) {
|
||||
return result.and_then(|binding| {
|
||||
if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
|
||||
binding.is_extern_crate() { // c.f. issue #37020
|
||||
Success(binding)
|
||||
} else {
|
||||
Failed(None)
|
||||
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
|
||||
let usable =
|
||||
this.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
|
||||
binding.is_extern_crate(); // c.f. issue #37020
|
||||
if usable { Success(binding) } else { Failed(None) }
|
||||
};
|
||||
|
||||
// Items and single imports are not shadowable.
|
||||
if let Some(binding) = resolution.binding {
|
||||
if !binding.is_glob_import() {
|
||||
return check_usable(self, binding);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a single import can still define the name.
|
||||
match resolution.single_imports {
|
||||
SingleImports::AtLeastOne => return Indeterminate,
|
||||
SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
|
||||
let module = match directive.imported_module.get() {
|
||||
Some(module) => module,
|
||||
None => return Indeterminate,
|
||||
};
|
||||
let name = match directive.subclass {
|
||||
SingleImport { source, .. } => source,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match self.resolve_name_in_module(module, name, ns, true, false, None) {
|
||||
Failed(_) => {}
|
||||
_ => return Indeterminate,
|
||||
}
|
||||
});
|
||||
}
|
||||
SingleImports::MaybeOne(_) | SingleImports::None => {},
|
||||
}
|
||||
|
||||
let no_unresolved_invocations =
|
||||
ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty();
|
||||
match resolution.binding {
|
||||
// In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`).
|
||||
Some(binding) if no_unresolved_invocations || ns == MacroNS =>
|
||||
return check_usable(self, binding),
|
||||
None if no_unresolved_invocations => {}
|
||||
_ => return Indeterminate,
|
||||
}
|
||||
|
||||
// Check if the globs are determined
|
||||
for directive in module.globs.borrow().iter() {
|
||||
if self.is_accessible(directive.vis.get()) {
|
||||
if let Some(module) = directive.imported_module.get() {
|
||||
let result = self.resolve_name_in_module(module, name, ns, true, None);
|
||||
let result = self.resolve_name_in_module(module, name, ns, true, false, None);
|
||||
if let Indeterminate = result {
|
||||
return Indeterminate;
|
||||
}
|
||||
|
@ -204,43 +237,6 @@ impl<'a> Resolver<'a> {
|
|||
Failed(None)
|
||||
}
|
||||
|
||||
// Returns Some(the resolution of the name), or None if the resolution depends
|
||||
// on whether more globs can define the name.
|
||||
fn try_result(&mut self, resolution: &NameResolution<'a>, module: Module<'a>, ns: Namespace)
|
||||
-> Option<ResolveResult<&'a NameBinding<'a>>> {
|
||||
match resolution.binding {
|
||||
Some(binding) if !binding.is_glob_import() =>
|
||||
return Some(Success(binding)), // Items and single imports are not shadowable.
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// Check if a single import can still define the name.
|
||||
match resolution.single_imports {
|
||||
SingleImports::AtLeastOne => return Some(Indeterminate),
|
||||
SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
|
||||
let module = match directive.imported_module.get() {
|
||||
Some(module) => module,
|
||||
None => return Some(Indeterminate),
|
||||
};
|
||||
let name = match directive.subclass {
|
||||
SingleImport { source, .. } => source,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match self.resolve_name_in_module(module, name, ns, true, None) {
|
||||
Failed(_) => {}
|
||||
_ => return Some(Indeterminate),
|
||||
}
|
||||
}
|
||||
SingleImports::MaybeOne(_) | SingleImports::None => {},
|
||||
}
|
||||
|
||||
if !module.unresolved_invocations.borrow().is_empty() {
|
||||
return Some(Indeterminate);
|
||||
}
|
||||
|
||||
resolution.binding.map(Success)
|
||||
}
|
||||
|
||||
// Add an import directive to the current module.
|
||||
pub fn add_import_directive(&mut self,
|
||||
module_path: Vec<Ident>,
|
||||
|
@ -315,29 +311,26 @@ impl<'a> Resolver<'a> {
|
|||
self.update_resolution(module, name, ns, |this, resolution| {
|
||||
if let Some(old_binding) = resolution.binding {
|
||||
if binding.is_glob_import() {
|
||||
if !this.new_import_semantics || !old_binding.is_glob_import() {
|
||||
if !this.new_import_semantics {
|
||||
resolution.duplicate_globs.push(binding);
|
||||
} else if !old_binding.is_glob_import() &&
|
||||
!(ns == MacroNS && old_binding.expansion != Mark::root()) {
|
||||
} else if binding.def() != old_binding.def() {
|
||||
resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Ambiguity {
|
||||
b1: old_binding,
|
||||
b2: binding,
|
||||
},
|
||||
vis: if old_binding.vis.is_at_least(binding.vis, this) {
|
||||
old_binding.vis
|
||||
} else {
|
||||
binding.vis
|
||||
},
|
||||
span: old_binding.span,
|
||||
expansion: Mark::root(),
|
||||
}));
|
||||
resolution.binding = Some(this.ambiguity(old_binding, binding));
|
||||
} else if !old_binding.vis.is_at_least(binding.vis, this) {
|
||||
// We are glob-importing the same item but with greater visibility.
|
||||
resolution.binding = Some(binding);
|
||||
}
|
||||
} else if old_binding.is_glob_import() {
|
||||
resolution.duplicate_globs.push(old_binding);
|
||||
resolution.binding = Some(binding);
|
||||
if !this.new_import_semantics {
|
||||
resolution.duplicate_globs.push(old_binding);
|
||||
resolution.binding = Some(binding);
|
||||
} else if ns == MacroNS && binding.expansion != Mark::root() &&
|
||||
binding.def() != old_binding.def() {
|
||||
resolution.binding = Some(this.ambiguity(binding, old_binding));
|
||||
} else {
|
||||
resolution.binding = Some(binding);
|
||||
}
|
||||
} else {
|
||||
return Err(old_binding);
|
||||
}
|
||||
|
@ -349,6 +342,16 @@ impl<'a> Resolver<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn ambiguity(&mut self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
|
||||
-> &'a NameBinding<'a> {
|
||||
self.arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Ambiguity { b1: b1, b2: b2 },
|
||||
vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
|
||||
span: b1.span,
|
||||
expansion: Mark::root(),
|
||||
})
|
||||
}
|
||||
|
||||
// Use `f` to mutate the resolution of the name in the module.
|
||||
// If the resolution becomes a success, define it in the module's glob importers.
|
||||
fn update_resolution<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T
|
||||
|
@ -525,7 +528,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
self.per_ns(|this, ns| {
|
||||
if let Err(Undetermined) = result[ns].get() {
|
||||
result[ns].set({
|
||||
match this.resolve_name_in_module(module, source, ns, false, None) {
|
||||
match this.resolve_name_in_module(module, source, ns, false, false, None) {
|
||||
Success(binding) => Ok(binding),
|
||||
Indeterminate => Err(Undetermined),
|
||||
Failed(_) => Err(Determined),
|
||||
|
@ -621,7 +624,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
if all_ns_err {
|
||||
let mut all_ns_failed = true;
|
||||
self.per_ns(|this, ns| {
|
||||
match this.resolve_name_in_module(module, name, ns, false, Some(span)) {
|
||||
match this.resolve_name_in_module(module, name, ns, false, false, Some(span)) {
|
||||
Success(_) => all_ns_failed = false,
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -314,6 +314,8 @@ declare_features! (
|
|||
|
||||
// Allows #[link(..., cfg(..))]
|
||||
(active, link_cfg, "1.14.0", Some(37406)),
|
||||
|
||||
(active, use_extern_macros, "1.15.0", Some(35896)),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
|
|
@ -46,9 +46,9 @@ mod g {
|
|||
fn main() {
|
||||
e::foo();
|
||||
f::foo(); //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
|
||||
//~| NOTE consider adding an explicit import of `foo` to disambiguate
|
||||
g::foo(); //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
|
||||
//~| NOTE consider adding an explicit import of `foo` to disambiguate
|
||||
}
|
||||
|
||||
mod ambiguous_module_errors {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue