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:
commit
c57b826149
14 changed files with 621 additions and 389 deletions
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
|
|||
|
|
@ -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, ¬e_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, ¬e_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(());
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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! (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
15
src/test/compile-fail/imports/auxiliary/two_macros.rs
Normal file
15
src/test/compile-fail/imports/auxiliary/two_macros.rs
Normal 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)* } }
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
55
src/test/compile-fail/imports/macros.rs
Normal file
55
src/test/compile-fail/imports/macros.rs
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue