Auto merge of #37732 - jseyfried:use_extern_macros, r=nrc

Support `use`ing externally defined macros behind `#![feature(use_extern_macros)]`

With `#![feature(use_extern_macros)]`,
 - A name collision between macros from different upstream crates is much less of an issue since we can `use` the macros in different submodules or rename with `as`.
 - We can reexport macros with `pub use`, so `#![feature(macro_reexport)]` is no longer needed.
 - These reexports are allowed in any module, so crates can expose a macro-modular interface.

If a macro invocation can resolve to both a `use` import and a `macro_rules!` or `#[macro_use]`, it is an ambiguity error.

r? @nrc
This commit is contained in:
bors 2016-11-17 07:43:50 -08:00 committed by GitHub
commit c57b826149
14 changed files with 621 additions and 389 deletions

View file

@ -755,8 +755,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|| ast_validation::check_crate(sess, &krate));
time(sess.time_passes(), "name resolution", || -> CompileResult {
resolver.resolve_imports();
// Since import resolution will eventually happen in expansion,
// don't perform `after_expand` until after import resolution.
after_expand(&krate)?;

View file

@ -15,7 +15,7 @@
use macros::{InvocationData, LegacyScope};
use resolve_imports::ImportDirective;
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
use Namespace::{self, TypeNS, ValueNS, MacroNS};
use ResolveResult::Success;
@ -37,6 +37,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::Undetermined;
use syntax::ext::expand::mark_tts;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
@ -45,15 +46,25 @@ use syntax::visit::{self, Visitor};
use syntax_pos::{Span, DUMMY_SP};
impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) {
impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
fn to_name_binding(self) -> NameBinding<'a> {
NameBinding { kind: NameBindingKind::Module(self.0), span: self.1, vis: self.2 }
NameBinding {
kind: NameBindingKind::Module(self.0),
vis: self.1,
span: self.2,
expansion: self.3,
}
}
}
impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
fn to_name_binding(self) -> NameBinding<'a> {
NameBinding { kind: NameBindingKind::Def(self.0), span: self.1, vis: self.2 }
NameBinding {
kind: NameBindingKind::Def(self.0),
vis: self.1,
span: self.2,
expansion: self.3,
}
}
}
@ -147,9 +158,14 @@ impl<'b> Resolver<'b> {
.emit();
}
let subclass = ImportDirectiveSubclass::single(binding.name, source.name);
let span = view_path.span;
self.add_import_directive(module_path, subclass, span, item.id, vis);
let subclass = SingleImport {
target: binding.name,
source: source.name,
result: self.per_ns(|_, _| Cell::new(Err(Undetermined))),
};
self.add_import_directive(
module_path, subclass, view_path.span, item.id, vis, expansion,
);
}
ViewPathList(_, ref source_items) => {
// Make sure there's at most one `mod` import in the list.
@ -195,9 +211,15 @@ impl<'b> Resolver<'b> {
(module_path.to_vec(), name, rename)
}
};
let subclass = ImportDirectiveSubclass::single(rename, name);
let (span, id) = (source_item.span, source_item.node.id);
self.add_import_directive(module_path, subclass, span, id, vis);
let subclass = SingleImport {
target: rename,
source: name,
result: self.per_ns(|_, _| Cell::new(Err(Undetermined))),
};
let id = source_item.node.id;
self.add_import_directive(
module_path, subclass, source_item.span, id, vis, expansion,
);
}
}
ViewPathGlob(_) => {
@ -205,8 +227,9 @@ impl<'b> Resolver<'b> {
is_prelude: is_prelude,
max_vis: Cell::new(ty::Visibility::PrivateExternal),
};
let span = view_path.span;
self.add_import_directive(module_path, subclass, span, item.id, vis);
self.add_import_directive(
module_path, subclass, view_path.span, item.id, vis, expansion,
);
}
}
}
@ -217,7 +240,7 @@ impl<'b> Resolver<'b> {
// n.b. we don't need to look at the path option here, because cstore already did
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
let module = self.get_extern_crate_root(crate_id);
let binding = (module, sp, ty::Visibility::Public).to_name_binding();
let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding();
let binding = self.arenas.alloc_name_binding(binding);
let directive = self.arenas.alloc_import_directive(ImportDirective {
id: item.id,
@ -227,6 +250,7 @@ impl<'b> Resolver<'b> {
span: item.span,
module_path: Vec::new(),
vis: Cell::new(vis),
expansion: expansion,
});
let imported_binding = self.import(binding, directive);
self.define(parent, name, TypeNS, imported_binding);
@ -245,7 +269,7 @@ impl<'b> Resolver<'b> {
normal_ancestor_id: Some(item.id),
..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
});
self.define(parent, name, TypeNS, (module, sp, vis));
self.define(parent, name, TypeNS, (module, vis, sp, expansion));
self.module_map.insert(item.id, module);
// Descend into the module.
@ -258,30 +282,30 @@ impl<'b> Resolver<'b> {
ItemKind::Static(_, m, _) => {
let mutbl = m == Mutability::Mutable;
let def = Def::Static(self.definitions.local_def_id(item.id), mutbl);
self.define(parent, name, ValueNS, (def, sp, vis));
self.define(parent, name, ValueNS, (def, vis, sp, expansion));
}
ItemKind::Const(..) => {
let def = Def::Const(self.definitions.local_def_id(item.id));
self.define(parent, name, ValueNS, (def, sp, vis));
self.define(parent, name, ValueNS, (def, vis, sp, expansion));
}
ItemKind::Fn(..) => {
let def = Def::Fn(self.definitions.local_def_id(item.id));
self.define(parent, name, ValueNS, (def, sp, vis));
self.define(parent, name, ValueNS, (def, vis, sp, expansion));
}
// These items live in the type namespace.
ItemKind::Ty(..) => {
let def = Def::TyAlias(self.definitions.local_def_id(item.id));
self.define(parent, name, TypeNS, (def, sp, vis));
self.define(parent, name, TypeNS, (def, vis, sp, expansion));
}
ItemKind::Enum(ref enum_definition, _) => {
let def = Def::Enum(self.definitions.local_def_id(item.id));
let module = self.new_module(parent, ModuleKind::Def(def, name), true);
self.define(parent, name, TypeNS, (module, sp, vis));
self.define(parent, name, TypeNS, (module, vis, sp, expansion));
for variant in &(*enum_definition).variants {
self.build_reduced_graph_for_variant(variant, module, vis);
self.build_reduced_graph_for_variant(variant, module, vis, expansion);
}
}
@ -289,14 +313,14 @@ impl<'b> Resolver<'b> {
ItemKind::Struct(ref struct_def, _) => {
// Define a name in the type namespace.
let def = Def::Struct(self.definitions.local_def_id(item.id));
self.define(parent, name, TypeNS, (def, sp, vis));
self.define(parent, name, TypeNS, (def, vis, sp, expansion));
// If this is a tuple or unit struct, define a name
// in the value namespace as well.
if !struct_def.is_struct() {
let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()),
CtorKind::from_ast(struct_def));
self.define(parent, name, ValueNS, (ctor_def, sp, vis));
self.define(parent, name, ValueNS, (ctor_def, vis, sp, expansion));
}
// Record field names for error reporting.
@ -310,7 +334,7 @@ impl<'b> Resolver<'b> {
ItemKind::Union(ref vdata, _) => {
let def = Def::Union(self.definitions.local_def_id(item.id));
self.define(parent, name, TypeNS, (def, sp, vis));
self.define(parent, name, TypeNS, (def, vis, sp, expansion));
// Record field names for error reporting.
let field_names = vdata.fields().iter().filter_map(|field| {
@ -329,7 +353,7 @@ impl<'b> Resolver<'b> {
// Add all the items within to a new module.
let module =
self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), name), true);
self.define(parent, name, TypeNS, (module, sp, vis));
self.define(parent, name, TypeNS, (module, vis, sp, expansion));
self.current_module = module;
}
ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
@ -341,37 +365,38 @@ impl<'b> Resolver<'b> {
fn build_reduced_graph_for_variant(&mut self,
variant: &Variant,
parent: Module<'b>,
vis: ty::Visibility) {
vis: ty::Visibility,
expansion: Mark) {
let name = variant.node.name.name;
let def_id = self.definitions.local_def_id(variant.node.data.id());
// Define a name in the type namespace.
let def = Def::Variant(def_id);
self.define(parent, name, TypeNS, (def, variant.span, vis));
self.define(parent, name, TypeNS, (def, vis, variant.span, expansion));
// Define a constructor name in the value namespace.
// Braced variants, unlike structs, generate unusable names in
// value namespace, they are reserved for possible future use.
let ctor_kind = CtorKind::from_ast(&variant.node.data);
let ctor_def = Def::VariantCtor(def_id, ctor_kind);
self.define(parent, name, ValueNS, (ctor_def, variant.span, vis));
self.define(parent, name, ValueNS, (ctor_def, vis, variant.span, expansion));
}
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem) {
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) {
let parent = self.current_module;
let name = foreign_item.ident.name;
let name = item.ident.name;
let def = match foreign_item.node {
let def = match item.node {
ForeignItemKind::Fn(..) => {
Def::Fn(self.definitions.local_def_id(foreign_item.id))
Def::Fn(self.definitions.local_def_id(item.id))
}
ForeignItemKind::Static(_, m) => {
Def::Static(self.definitions.local_def_id(foreign_item.id), m)
Def::Static(self.definitions.local_def_id(item.id), m)
}
};
let vis = self.resolve_visibility(&foreign_item.vis);
self.define(parent, name, ValueNS, (def, foreign_item.span, vis));
let vis = self.resolve_visibility(&item.vis);
self.define(parent, name, ValueNS, (def, vis, item.span, expansion));
}
fn build_reduced_graph_for_block(&mut self, block: &Block) {
@ -390,8 +415,7 @@ impl<'b> Resolver<'b> {
}
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>,
child: Export) {
fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) {
let name = child.name;
let def = child.def;
let def_id = def.def_id();
@ -404,24 +428,24 @@ impl<'b> Resolver<'b> {
match def {
Def::Mod(..) | Def::Enum(..) => {
let module = self.new_module(parent, ModuleKind::Def(def, name), false);
self.define(parent, name, TypeNS, (module, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
}
Def::Variant(..) => {
self.define(parent, name, TypeNS, (def, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::VariantCtor(..) => {
self.define(parent, name, ValueNS, (def, DUMMY_SP, vis));
self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Fn(..) |
Def::Static(..) |
Def::Const(..) |
Def::AssociatedConst(..) |
Def::Method(..) => {
self.define(parent, name, ValueNS, (def, DUMMY_SP, vis));
self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Trait(..) => {
let module = self.new_module(parent, ModuleKind::Def(def, name), false);
self.define(parent, name, TypeNS, (module, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
// If this is a trait, add all the trait item names to the trait info.
let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id);
@ -433,27 +457,27 @@ impl<'b> Resolver<'b> {
}
}
Def::TyAlias(..) | Def::AssociatedTy(..) => {
self.define(parent, name, TypeNS, (def, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Struct(..) => {
self.define(parent, name, TypeNS, (def, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
// Record field names for error reporting.
let field_names = self.session.cstore.struct_field_names(def_id);
self.insert_field_names(def_id, field_names);
}
Def::StructCtor(..) => {
self.define(parent, name, ValueNS, (def, DUMMY_SP, vis));
self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Union(..) => {
self.define(parent, name, TypeNS, (def, DUMMY_SP, vis));
self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
// Record field names for error reporting.
let field_names = self.session.cstore.struct_field_names(def_id);
self.insert_field_names(def_id, field_names);
}
Def::Macro(..) => {
self.define(parent, name, MacroNS, (def, DUMMY_SP, vis));
self.define(parent, name, MacroNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Local(..) |
Def::PrimTy(..) |
@ -479,9 +503,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) {
@ -518,10 +544,14 @@ impl<'b> Resolver<'b> {
module.populated.set(true)
}
fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) {
self.used_crates.insert(def.def_id().krate);
fn legacy_import_macro(&mut self,
name: Name,
binding: &'b NameBinding<'b>,
span: Span,
allow_shadowing: bool) {
self.used_crates.insert(binding.def().def_id().krate);
self.macro_names.insert(name);
if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing {
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
let msg = format!("`{}` is already in scope", name);
let note =
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
@ -548,13 +578,13 @@ impl<'b> Resolver<'b> {
if let Some(span) = legacy_imports.import_all {
module.for_each_child(|name, ns, binding| if ns == MacroNS {
self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
self.legacy_import_macro(name, binding, span, allow_shadowing);
});
} 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.def(), span, allow_shadowing);
self.legacy_import_macro(name, binding, span, allow_shadowing);
} else {
span_err!(self.session, span, E0469, "imported macro not found");
}
@ -562,7 +592,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 {
@ -638,7 +668,9 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)];
let mark = Mark::from_placeholder_id(id);
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
let invocation = self.resolver.invocations[&mark];
invocation.module.set(self.resolver.current_module);
invocation.legacy_scope.set(self.legacy_scope);
invocation
@ -691,7 +723,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
}
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
self.resolver.build_reduced_graph_for_foreign_item(foreign_item);
self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
visit::walk_foreign_item(self, foreign_item);
}
@ -728,7 +760,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
let vis = ty::Visibility::Public;
self.resolver.define(parent, item.ident.name, ns, (def, item.span, vis));
self.resolver.define(parent, item.ident.name, ns, (def, vis, item.span, self.expansion));
self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor
visit::walk_trait_item(self, item);

View file

@ -22,7 +22,6 @@
use std::ops::{Deref, DerefMut};
use Resolver;
use Namespace::{TypeNS, ValueNS};
use rustc::lint;
use rustc::util::nodemap::NodeMap;
@ -56,8 +55,9 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
// We have information about whether `use` (import) directives are actually
// used now. If an import is not used at all, we signal a lint error.
fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) {
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
let mut used = false;
self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
if !used {
if self.maybe_unused_trait_imports.contains(&id) {
// Check later.
return;

View file

@ -76,7 +76,7 @@ use std::fmt;
use std::mem::replace;
use std::rc::Rc;
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution};
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
use macros::{InvocationData, LegacyBinding, LegacyScope};
// NB: This module needs to be declared first so diagnostics are
@ -536,6 +536,34 @@ pub enum Namespace {
MacroNS,
}
#[derive(Clone, Default, Debug)]
pub struct PerNS<T> {
value_ns: T,
type_ns: T,
macro_ns: Option<T>,
}
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
type Output = T;
fn index(&self, ns: Namespace) -> &T {
match ns {
ValueNS => &self.value_ns,
TypeNS => &self.type_ns,
MacroNS => self.macro_ns.as_ref().unwrap(),
}
}
}
impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
fn index_mut(&mut self, ns: Namespace) -> &mut T {
match ns {
ValueNS => &mut self.value_ns,
TypeNS => &mut self.type_ns,
MacroNS => self.macro_ns.as_mut().unwrap(),
}
}
}
impl<'a> Visitor for Resolver<'a> {
fn visit_item(&mut self, item: &Item) {
self.resolve_item(item);
@ -612,7 +640,7 @@ impl<'a> Visitor for Resolver<'a> {
};
// Create a value rib for the function.
self.value_ribs.push(Rib::new(rib_kind));
self.ribs[ValueNS].push(Rib::new(rib_kind));
// Create a label rib for the function.
self.label_ribs.push(Rib::new(rib_kind));
@ -642,13 +670,13 @@ impl<'a> Visitor for Resolver<'a> {
debug!("(resolving function) leaving function");
self.label_ribs.pop();
self.value_ribs.pop();
self.ribs[ValueNS].pop();
}
}
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.
@ -656,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),
@ -798,6 +818,10 @@ 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>>,
no_implicit_prelude: bool,
@ -822,6 +846,8 @@ 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()),
globs: RefCell::new((Vec::new())),
@ -877,6 +903,7 @@ impl<'a> fmt::Debug for ModuleS<'a> {
#[derive(Clone, Debug)]
pub struct NameBinding<'a> {
kind: NameBindingKind<'a>,
expansion: Mark,
span: Span,
vis: ty::Visibility,
}
@ -911,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>,
}
@ -969,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,
}
}
@ -1044,12 +1072,9 @@ pub struct Resolver<'a> {
// The module that represents the current item scope.
current_module: Module<'a>,
// The current set of local scopes, for values.
// The current set of local scopes for types and values.
// FIXME #4948: Reuse ribs to avoid allocation.
value_ribs: Vec<Rib<'a>>,
// The current set of local scopes, for types.
type_ribs: Vec<Rib<'a>>,
ribs: PerNS<Vec<Rib<'a>>>,
// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a>>,
@ -1107,11 +1132,12 @@ 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,
macro_names: FxHashSet<Name>,
builtin_macros: FxHashMap<Name, DefId>,
builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>,
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
macro_exports: Vec<Export>,
@ -1268,8 +1294,11 @@ impl<'a> Resolver<'a> {
indeterminate_imports: Vec::new(),
current_module: graph_root,
value_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
type_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
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(),
current_trait_ref: None,
@ -1300,10 +1329,12 @@ impl<'a> Resolver<'a> {
arenas: arenas,
dummy_binding: arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Def(Def::Err),
expansion: Mark::root(),
span: DUMMY_SP,
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,
@ -1329,8 +1360,20 @@ impl<'a> Resolver<'a> {
}
}
fn per_ns<T, F: FnMut(&mut Self, Namespace) -> T>(&mut self, mut f: F) -> PerNS<T> {
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,
},
}
}
/// Entry point to crate resolution.
pub fn resolve_crate(&mut self, krate: &Crate) {
ImportResolver { resolver: self }.finalize_imports();
self.current_module = self.graph_root;
visit::walk_crate(self, krate);
@ -1347,14 +1390,6 @@ impl<'a> Resolver<'a> {
})
}
fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
match ns {
ValueNS => &mut self.value_ribs,
TypeNS => &mut self.type_ribs,
MacroNS => panic!("The macro namespace has no ribs"),
}
}
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
-> bool /* true if an error was reported */ {
// track extern crates for unused_extern_crate lint
@ -1371,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
@ -1406,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)
@ -1424,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);
@ -1570,8 +1606,8 @@ impl<'a> Resolver<'a> {
}
// Walk backwards up the ribs in scope.
for i in (0 .. self.get_ribs(ns).len()).rev() {
if let Some(def) = self.get_ribs(ns)[i].bindings.get(&ident).cloned() {
for i in (0 .. self.ribs[ns].len()).rev() {
if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::LocalDef(LocalDef {
ribs: Some((ns, i)),
@ -1579,9 +1615,9 @@ impl<'a> Resolver<'a> {
}));
}
if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind {
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));
@ -1590,14 +1626,14 @@ 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;
}
}
if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind {
if let MacroDefinition(mac) = self.ribs[ns][i].kind {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
let (source_ctxt, source_macro) = ident.ctxt.source();
@ -1682,14 +1718,15 @@ impl<'a> Resolver<'a> {
if let Some(module) = module {
// Move down in the graph.
let orig_module = replace(&mut self.current_module, module);
self.value_ribs.push(Rib::new(ModuleRibKind(module)));
self.type_ribs.push(Rib::new(ModuleRibKind(module)));
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;
self.value_ribs.pop();
self.type_ribs.pop();
self.ribs[ValueNS].pop();
self.ribs[TypeNS].pop();
} else {
f(self);
}
@ -1864,7 +1901,7 @@ impl<'a> Resolver<'a> {
function_type_rib.bindings.insert(Ident::with_empty_ctxt(name), def);
self.record_def(type_parameter.id, PathResolution::new(def));
}
self.type_ribs.push(function_type_rib);
self.ribs[TypeNS].push(function_type_rib);
}
NoTypeParameters => {
@ -1875,7 +1912,7 @@ impl<'a> Resolver<'a> {
f(self);
if let HasTypeParameters(..) = type_parameters {
self.type_ribs.pop();
self.ribs[TypeNS].pop();
}
}
@ -1890,11 +1927,11 @@ impl<'a> Resolver<'a> {
fn with_constant_rib<F>(&mut self, f: F)
where F: FnOnce(&mut Resolver)
{
self.value_ribs.push(Rib::new(ConstantItemRibKind));
self.type_ribs.push(Rib::new(ConstantItemRibKind));
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
self.ribs[TypeNS].push(Rib::new(ConstantItemRibKind));
f(self);
self.type_ribs.pop();
self.value_ribs.pop();
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
}
fn resolve_trait_reference(&mut self,
@ -2004,9 +2041,9 @@ impl<'a> Resolver<'a> {
// plain insert (no renaming, types are not currently hygienic....)
self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def);
self.type_ribs.push(self_type_rib);
self.ribs[TypeNS].push(self_type_rib);
f(self);
self.type_ribs.pop();
self.ribs[TypeNS].pop();
}
fn resolve_implementation(&mut self,
@ -2160,7 +2197,7 @@ impl<'a> Resolver<'a> {
}
fn resolve_arm(&mut self, arm: &Arm) {
self.value_ribs.push(Rib::new(NormalRibKind));
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
let mut bindings_list = FxHashMap();
for pattern in &arm.pats {
@ -2174,7 +2211,7 @@ impl<'a> Resolver<'a> {
walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&arm.body);
self.value_ribs.pop();
self.ribs[ValueNS].pop();
}
fn resolve_block(&mut self, block: &Block) {
@ -2186,11 +2223,12 @@ impl<'a> Resolver<'a> {
let mut num_macro_definition_ribs = 0;
if let Some(anonymous_module) = anonymous_module {
debug!("(resolving block) found anonymous module, moving down");
self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
self.type_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
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.value_ribs.push(Rib::new(NormalRibKind));
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
}
// Descend into the block.
@ -2198,7 +2236,7 @@ impl<'a> Resolver<'a> {
if let Some(marks) = self.macros_at_scope.remove(&stmt.id) {
num_macro_definition_ribs += marks.len() as u32;
for mark in marks {
self.value_ribs.push(Rib::new(MacroDefinition(mark)));
self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark)));
self.label_ribs.push(Rib::new(MacroDefinition(mark)));
}
}
@ -2209,12 +2247,12 @@ impl<'a> Resolver<'a> {
// Move back up.
self.current_module = orig_module;
for _ in 0 .. num_macro_definition_ribs {
self.value_ribs.pop();
self.ribs[ValueNS].pop();
self.label_ribs.pop();
}
self.value_ribs.pop();
self.ribs[ValueNS].pop();
if let Some(_) = anonymous_module {
self.type_ribs.pop();
self.ribs[TypeNS].pop();
}
debug!("(resolving block) leaving block");
}
@ -2333,7 +2371,7 @@ impl<'a> Resolver<'a> {
Some(..) if pat_src == PatternSource::Match => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
def = self.value_ribs.last_mut().unwrap().bindings[&ident.node];
def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
}
Some(..) => {
span_bug!(ident.span, "two bindings with the same name from \
@ -2343,7 +2381,7 @@ impl<'a> Resolver<'a> {
// A completely fresh binding, add to the lists if it's valid.
if ident.node.name != keywords::Invalid.name() {
bindings.insert(ident.node, outer_pat_id);
self.value_ribs.last_mut().unwrap().bindings.insert(ident.node, def);
self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident.node, def);
}
}
}
@ -2627,9 +2665,8 @@ impl<'a> Resolver<'a> {
// Resolve a local definition, potentially adjusting for closures.
fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
let ribs = match local_def.ribs {
Some((TypeNS, i)) => &self.type_ribs[i + 1..],
Some((ValueNS, i)) => &self.value_ribs[i + 1..],
_ => &[] as &[_],
Some((ns, i)) => &self.ribs[ns][i + 1..],
None => &[] as &[_],
};
let mut def = local_def.def;
match def {
@ -2723,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));
@ -2732,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)
}
@ -2751,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));
@ -2764,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)
}
@ -2791,8 +2820,8 @@ impl<'a> Resolver<'a> {
where F: FnOnce(&mut Resolver<'a>) -> T,
{
self.with_empty_ribs(|this| {
this.value_ribs.push(Rib::new(ModuleRibKind(module)));
this.type_ribs.push(Rib::new(ModuleRibKind(module)));
this.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
this.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
f(this)
})
}
@ -2800,13 +2829,11 @@ impl<'a> Resolver<'a> {
fn with_empty_ribs<T, F>(&mut self, f: F) -> T
where F: FnOnce(&mut Resolver<'a>) -> T,
{
let value_ribs = replace(&mut self.value_ribs, Vec::new());
let type_ribs = replace(&mut self.type_ribs, Vec::new());
let ribs = replace(&mut self.ribs, PerNS::<Vec<Rib>>::default());
let label_ribs = replace(&mut self.label_ribs, Vec::new());
let result = f(self);
self.value_ribs = value_ribs;
self.type_ribs = type_ribs;
self.ribs = ribs;
self.label_ribs = label_ribs;
result
}
@ -2858,7 +2885,7 @@ impl<'a> Resolver<'a> {
return SuggestionType::Macro(format!("{}!", macro_name));
}
let names = self.value_ribs
let names = self.ribs[ValueNS]
.iter()
.rev()
.flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name));
@ -2961,7 +2988,7 @@ impl<'a> Resolver<'a> {
} else {
let mut method_scope = false;
let mut is_static = false;
self.value_ribs.iter().rev().all(|rib| {
self.ribs[ValueNS].iter().rev().all(|rib| {
method_scope = match rib.kind {
MethodRibKind(is_static_) => {
is_static = is_static_;
@ -3072,10 +3099,10 @@ impl<'a> Resolver<'a> {
ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
self.visit_expr(subexpression);
self.value_ribs.push(Rib::new(NormalRibKind));
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap());
self.visit_block(if_block);
self.value_ribs.pop();
self.ribs[ValueNS].pop();
optional_else.as_ref().map(|expr| self.visit_expr(expr));
}
@ -3089,22 +3116,22 @@ impl<'a> Resolver<'a> {
ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
self.visit_expr(subexpression);
self.value_ribs.push(Rib::new(NormalRibKind));
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
self.resolve_labeled_block(label, expr.id, block);
self.value_ribs.pop();
self.ribs[ValueNS].pop();
}
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
self.visit_expr(subexpression);
self.value_ribs.push(Rib::new(NormalRibKind));
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap());
self.resolve_labeled_block(label, expr.id, block);
self.value_ribs.pop();
self.ribs[ValueNS].pop();
}
ExprKind::Field(ref subexpression, _) => {
@ -3354,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();
}
@ -3384,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)

View file

@ -8,14 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use {Module, ModuleKind, 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};
use rustc::hir::def::{Def, Export};
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};
@ -27,7 +31,7 @@ use syntax::parse::token::intern;
use syntax::ptr::P;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::Visitor;
use syntax_pos::Span;
use syntax_pos::{Span, DUMMY_SP};
#[derive(Clone)]
pub struct InvocationData<'a> {
@ -83,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()
@ -131,12 +140,14 @@ impl<'a> base::Resolver for Resolver<'a> {
self.collect_def_ids(invocation, expansion);
self.current_module = invocation.module.get();
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
let mut visitor = BuildReducedGraphVisitor {
resolver: self,
legacy_scope: LegacyScope::Invocation(invocation),
expansion: mark,
};
expansion.visit_with(&mut visitor);
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
invocation.expansion.set(visitor.legacy_scope);
}
@ -177,18 +188,28 @@ impl<'a> base::Resolver for Resolver<'a> {
index: DefIndex::new(self.macro_map.len()),
};
self.macro_map.insert(def_id, ext);
self.builtin_macros.insert(ident.name, def_id);
let binding = self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Def(Def::Macro(def_id)),
span: DUMMY_SP,
vis: ty::Visibility::PrivateExternal,
expansion: Mark::root(),
});
self.builtin_macros.insert(ident.name, binding);
}
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
self.macros_at_scope.insert(id, macros);
}
fn resolve_imports(&mut self) {
ImportResolver { resolver: self }.resolve_imports()
}
fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
for i in 0..attrs.len() {
let name = intern(&attrs[i].name());
match self.builtin_macros.get(&name) {
Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) {
match self.builtin_macros.get(&name).cloned() {
Some(binding) => match *self.get_macro(binding) {
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
return Some(attrs.remove(i))
}
@ -212,25 +233,81 @@ 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: 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,
@ -249,25 +326,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(|def_id| self.get_macro(Def::Macro(def_id)))
}
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {

View file

@ -10,8 +10,8 @@
use self::ImportDirectiveSubclass::*;
use Module;
use Namespace::{self, TypeNS, ValueNS};
use {Module, PerNS};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding};
use ResolveResult;
use ResolveResult::*;
@ -26,26 +26,20 @@ use rustc::hir::def::*;
use syntax::ast::{Ident, NodeId, Name};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
use std::cell::{Cell, RefCell};
use std::mem;
impl<'a> Resolver<'a> {
pub fn resolve_imports(&mut self) {
ImportResolver { resolver: self }.resolve_imports();
}
}
/// Contains data for specific types of import directives.
#[derive(Clone, Debug)]
pub enum ImportDirectiveSubclass<'a> {
SingleImport {
target: Name,
source: Name,
value_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
type_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
},
GlobImport {
is_prelude: bool,
@ -55,17 +49,6 @@ pub enum ImportDirectiveSubclass<'a> {
ExternCrate,
}
impl<'a> ImportDirectiveSubclass<'a> {
pub fn single(target: Name, source: Name) -> Self {
SingleImport {
target: target,
source: source,
type_result: Cell::new(Err(Undetermined)),
value_result: Cell::new(Err(Undetermined)),
}
}
}
/// One import directive.
#[derive(Debug,Clone)]
pub struct ImportDirective<'a> {
@ -76,6 +59,7 @@ pub struct ImportDirective<'a> {
pub subclass: ImportDirectiveSubclass<'a>,
pub span: Span,
pub vis: Cell<ty::Visibility>,
pub expansion: Mark,
}
impl<'a> ImportDirective<'a> {
@ -158,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);
@ -191,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, 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;
}
@ -220,46 +237,14 @@ 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>, 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 => {},
}
resolution.binding.map(Success)
}
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
module_path: Vec<Ident>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
vis: ty::Visibility) {
vis: ty::Visibility,
expansion: Mark) {
let current_module = self.current_module;
let directive = self.arenas.alloc_import_directive(ImportDirective {
parent: current_module,
@ -269,15 +254,16 @@ impl<'a> Resolver<'a> {
span: span,
id: id,
vis: Cell::new(vis),
expansion: expansion,
});
self.indeterminate_imports.push(directive);
match directive.subclass {
SingleImport { target, .. } => {
for &ns in &[ValueNS, TypeNS] {
let mut resolution = self.resolution(current_module, target, ns).borrow_mut();
self.per_ns(|this, ns| {
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
resolution.single_imports.add_directive(directive);
}
});
}
// We don't add prelude imports to the globs since they only affect lexical scopes,
// which are not relevant to import resolution.
@ -312,6 +298,7 @@ impl<'a> Resolver<'a> {
},
span: directive.span,
vis: vis,
expansion: directive.expansion,
}
}
@ -324,28 +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,
}));
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);
}
@ -357,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
@ -393,10 +388,22 @@ impl<'a> Resolver<'a> {
t
}
// Define a "dummy" resolution containing a Def::Err as a placeholder for a
// failed resolution
fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) {
if let SingleImport { target, .. } = directive.subclass {
let dummy_binding = self.dummy_binding;
let dummy_binding = self.import(dummy_binding, directive);
self.per_ns(|this, ns| {
let _ = this.try_define(directive.parent, target, ns, dummy_binding.clone());
});
}
}
}
struct ImportResolver<'a, 'b: 'a> {
resolver: &'a mut Resolver<'b>,
pub struct ImportResolver<'a, 'b: 'a> {
pub resolver: &'a mut Resolver<'b>,
}
impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> {
@ -429,28 +436,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
/// Resolves all imports for the crate. This method performs the fixed-
/// point iteration.
fn resolve_imports(&mut self) {
let mut i = 0;
pub fn resolve_imports(&mut self) {
let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
while self.indeterminate_imports.len() < prev_num_indeterminates {
prev_num_indeterminates = self.indeterminate_imports.len();
debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates);
let mut imports = Vec::new();
::std::mem::swap(&mut imports, &mut self.indeterminate_imports);
for import in imports {
for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) {
match self.resolve_import(&import) {
Failed(_) => self.determined_imports.push(import),
Indeterminate => self.indeterminate_imports.push(import),
Success(()) => self.determined_imports.push(import),
}
}
i += 1;
}
}
pub fn finalize_imports(&mut self) {
for module in self.arenas.local_modules().iter() {
self.finalize_resolutions_in(module);
}
@ -484,17 +484,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
}
}
// Define a "dummy" resolution containing a Def::Err as a placeholder for a
// failed resolution
fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) {
if let SingleImport { target, .. } = directive.subclass {
let dummy_binding = self.dummy_binding;
let dummy_binding = self.import(dummy_binding, directive);
let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone());
let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding);
}
}
/// Attempts to resolve the given import. The return value indicates
/// failure if we're certain the name does not exist, indeterminate if we
/// don't know whether the name exists at the moment due to other
@ -526,9 +515,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
};
directive.imported_module.set(Some(module));
let (source, target, value_result, type_result) = match directive.subclass {
SingleImport { source, target, ref value_result, ref type_result } =>
(source, target, value_result, type_result),
let (source, target, result) = match directive.subclass {
SingleImport { source, target, ref result } => (source, target, result),
GlobImport { .. } => {
self.resolve_glob_import(directive);
return Success(());
@ -537,46 +525,45 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
};
let mut indeterminate = false;
for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
if let Err(Undetermined) = result.get() {
result.set({
match self.resolve_name_in_module(module, source, ns, false, None) {
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, false, None) {
Success(binding) => Ok(binding),
Indeterminate => Err(Undetermined),
Failed(_) => Err(Determined),
}
});
} else {
continue
return
};
match result.get() {
match result[ns].get() {
Err(Undetermined) => indeterminate = true,
Err(Determined) => {
self.update_resolution(directive.parent, target, ns, |_, resolution| {
this.update_resolution(directive.parent, target, ns, |_, resolution| {
resolution.single_imports.directive_failed()
});
}
Ok(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
struct_span_err!(self.session, directive.span, E0253, "{}", &msg)
struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
.span_label(directive.span, &format!("cannot be imported directly"))
.emit();
// Do not import this illegal binding. Import a dummy binding and pretend
// everything is fine
self.import_dummy_binding(directive);
return Success(());
this.import_dummy_binding(directive);
}
Ok(binding) => {
let imported_binding = self.import(binding, directive);
let conflict = self.try_define(directive.parent, target, ns, imported_binding);
let imported_binding = this.import(binding, directive);
let conflict = this.try_define(directive.parent, target, ns, imported_binding);
if let Err(old_binding) = conflict {
let binding = &self.import(binding, directive);
self.report_conflict(directive.parent, target, ns, binding, old_binding);
let binding = &this.import(binding, directive);
this.report_conflict(directive.parent, target, ns, binding, old_binding);
}
}
}
}
});
if indeterminate { Indeterminate } else { Success(()) }
}
@ -604,9 +591,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
},
};
let (name, value_result, type_result) = match directive.subclass {
SingleImport { source, ref value_result, ref type_result, .. } =>
(source, value_result.get(), type_result.get()),
let (name, result) = match directive.subclass {
SingleImport { source, ref result, .. } => (source, result),
GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
// Importing a module into itself is not allowed.
let msg = "Cannot glob-import a module into itself.".into();
@ -624,21 +610,27 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
_ => unreachable!(),
};
for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
if let Ok(binding) = result {
if self.record_use(name, ns, binding, directive.span) {
self.resolution(module, name, ns).borrow_mut().binding =
Some(self.dummy_binding);
let mut all_ns_err = true;
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
all_ns_err = false;
if this.record_use(name, ns, binding, directive.span) {
this.resolution(module, name, ns).borrow_mut().binding =
Some(this.dummy_binding);
}
}
}
});
if value_result.is_err() && type_result.is_err() {
let (value_result, type_result);
value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span));
type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span));
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, false, Some(span)) {
Success(_) => all_ns_failed = false,
_ => {}
}
});
return if let (Failed(_), Failed(_)) = (value_result, type_result) {
return if all_ns_failed {
let resolutions = module.resolutions.borrow();
let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| {
if *n == name { return None; } // Never suggest the same name
@ -666,64 +658,49 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
}
}
let session = self.session;
let reexport_error = || {
let msg = format!("`{}` is private, and cannot be reexported", name);
let note_msg =
format!("consider marking `{}` as `pub` in the imported module", name);
struct_span_err!(session, directive.span, E0364, "{}", &msg)
.span_note(directive.span, &note_msg)
.emit();
};
let extern_crate_lint = || {
let msg = format!("extern crate `{}` is private, and cannot be reexported \
(error E0364), consider declaring with `pub`",
name);
session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
};
match (value_result, type_result) {
// All namespaces must be re-exported with extra visibility for an error to occur.
(Ok(value_binding), Ok(type_binding)) => {
let mut reexport_error = None;
let mut any_successful_reexport = false;
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
let vis = directive.vis.get();
if !value_binding.pseudo_vis().is_at_least(vis, self) &&
!type_binding.pseudo_vis().is_at_least(vis, self) {
reexport_error();
} else if type_binding.is_extern_crate() &&
!type_binding.vis.is_at_least(vis, self) {
extern_crate_lint();
}
}
(Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
reexport_error();
}
(_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
if binding.is_extern_crate() {
extern_crate_lint();
if !binding.pseudo_vis().is_at_least(vis, this) {
reexport_error = Some((ns, binding));
} else {
struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be reexported", name)
.span_label(directive.span, &format!("reexport of private `{}`", name))
.note(&format!("consider declaring type or module `{}` with `pub`", name))
.emit();
any_successful_reexport = true;
}
}
});
_ => {}
// All namespaces must be re-exported with extra visibility for an error to occur.
if !any_successful_reexport {
let (ns, binding) = reexport_error.unwrap();
if ns == TypeNS && binding.is_extern_crate() {
let msg = format!("extern crate `{}` is private, and cannot be reexported \
(error E0364), consider declaring with `pub`",
name);
self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
} else if ns == TypeNS {
struct_span_err!(self.session, directive.span, E0365,
"`{}` is private, and cannot be reexported", name)
.span_label(directive.span, &format!("reexport of private `{}`", name))
.note(&format!("consider declaring type or module `{}` with `pub`", name))
.emit();
} else {
let msg = format!("`{}` is private, and cannot be reexported", name);
let note_msg =
format!("consider marking `{}` as `pub` in the imported module", name);
struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
.span_note(directive.span, &note_msg)
.emit();
}
}
// Record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
let def = match type_result.ok().map(NameBinding::def) {
Some(def) => def,
None => value_result.ok().map(NameBinding::def).unwrap(),
};
let path_resolution = PathResolution::new(def);
self.def_map.insert(directive.id, path_resolution);
self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
});
debug!("(resolving single import) successfully resolved import");
return Success(());

View file

@ -524,6 +524,7 @@ pub trait Resolver {
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
fn resolve_imports(&mut self);
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
@ -547,6 +548,7 @@ impl Resolver for DummyResolver {
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
fn resolve_imports(&mut self) {}
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {

View file

@ -222,6 +222,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.current_expansion.depth = 0;
let (expansion, mut invocations) = self.collect_invocations(expansion);
self.resolve_imports();
invocations.reverse();
let mut expansions = Vec::new();
@ -230,9 +231,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
loop {
let invoc = if let Some(invoc) = invocations.pop() {
invoc
} else if undetermined_invocations.is_empty() {
break
} else {
self.resolve_imports();
if undetermined_invocations.is_empty() { break }
invocations = mem::replace(&mut undetermined_invocations, Vec::new());
force = !mem::replace(&mut progress, false);
continue
@ -292,6 +293,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
expansion.fold_with(&mut placeholder_expander)
}
fn resolve_imports(&mut self) {
if self.monotonic {
let err_count = self.cx.parse_sess.span_diagnostic.err_count();
self.cx.resolver.resolve_imports();
self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
}
}
fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
let result = {
let mut collector = InvocationCollector {

View file

@ -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! (

View file

@ -14,6 +14,6 @@ fn main() {
{
struct Bar;
use foo::Bar;
//~^ ERROR a value named `Bar` has already been defined in this block
//~^ ERROR a type named `Bar` has already been defined in this block
}
}

View file

@ -11,7 +11,7 @@
mod foo {
pub use self::bar::X;
use self::bar::X;
//~^ ERROR a value named `X` has already been imported in this module
//~^ ERROR a type named `X` has already been imported in this module
mod bar {
pub struct X;

View file

@ -0,0 +1,15 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_export]
macro_rules! m { ($($t:tt)*) => { $($t)* } }
#[macro_export]
macro_rules! n { ($($t:tt)*) => { $($t)* } }

View file

@ -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 {

View file

@ -0,0 +1,55 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:two_macros.rs
#![feature(item_like_imports, use_extern_macros)]
extern crate two_macros; // two identity macros `m` and `n`
mod foo {
pub use two_macros::n as m;
}
mod m1 {
m!(use two_macros::*;);
use foo::m; // This shadows the glob import
}
mod m2 {
use two_macros::*; //~ NOTE could also resolve
m! { //~ ERROR ambiguous
//~| NOTE macro-expanded macro imports do not shadow
use foo::m; //~ NOTE could resolve to the name imported here
//~^^^ NOTE in this expansion
}
}
mod m3 {
use two_macros::m; //~ NOTE could also resolve
fn f() {
use two_macros::n as m; // This shadows the above import
m!();
}
fn g() {
m! { //~ ERROR ambiguous
//~| NOTE macro-expanded macro imports do not shadow
use two_macros::n as m; //~ NOTE could resolve to the name imported here
//~^^^ NOTE in this expansion
}
}
}
mod m4 {
macro_rules! m { () => {} } //~ NOTE could resolve to the macro defined here
use two_macros::m; //~ NOTE could also resolve to the macro imported here
m!(); //~ ERROR ambiguous
}