Auto merge of #31461 - jseyfried:remove_import_resolutions, r=nrc
This PR adds to `NameBinding` so it can more fully represent bindings from imports as well from items, refactors away `Target`, generalizes `ImportResolution` to a simpler type `NameResolution`, and uses a single `NameResolution`-valued map in place the existing maps `children` and `import_resolutions` (of `NameBinding`s and `ImportResolution`s, respectively), simplifying duplicate checking and name resolution. It also unifies the `resolve_name_in_module` in `lib.rs` with its namesake in `resolve_imports.rs`, clarifying and improving the core logic (fixes #31403 and fixes #31404) while maintaining clear future-comparability with shadowable globs (i.e., never reporting that a resolution is a `Success` or is `Failing` unless this would also be knowable with shadowable globs). Since it fixes #31403, this is technically a [breaking-change], but it is exceedingly unlikely to cause breakage in practice. The following is an example of code that would break: ```rust mod foo { pub mod bar {} // This defines bar in the type namespace pub use alpha::bar; // This defines bar in the value namespace // This should define baz in both namespaces, but it only defines baz in the type namespace. pub use self::bar as baz; pub fn baz() {} // This should collide with baz, but now it does not. } pub fn f() {} mod alpha { pub use self::f as bar; // Changing this to `pub fn bar() {}` causes the collision right now. pub use super::*; } ``` r? @nrc
This commit is contained in:
commit
1de70d33f7
|
@ -16,10 +16,9 @@
|
|||
use DefModifiers;
|
||||
use resolve_imports::ImportDirective;
|
||||
use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport};
|
||||
use resolve_imports::ImportResolution;
|
||||
use Module;
|
||||
use Namespace::{self, TypeNS, ValueNS};
|
||||
use {NameBinding, DefOrModule};
|
||||
use {NameBinding, NameBindingKind};
|
||||
use {names_to_string, module_to_string};
|
||||
use ParentLink::{ModuleParentLink, BlockParentLink};
|
||||
use Resolver;
|
||||
|
@ -82,8 +81,8 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, Span) {
|
|||
|
||||
impl<'a> ToNameBinding<'a> for (Def, Span, DefModifiers) {
|
||||
fn to_name_binding(self) -> NameBinding<'a> {
|
||||
let def = DefOrModule::Def(self.0);
|
||||
NameBinding { modifiers: self.2, def_or_module: def, span: Some(self.1) }
|
||||
let kind = NameBindingKind::Def(self.0);
|
||||
NameBinding { modifiers: self.2, kind: kind, span: Some(self.1) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,16 +100,16 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||
fn try_define<T>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
|
||||
where T: ToNameBinding<'b>
|
||||
{
|
||||
parent.try_define_child(name, ns, def.to_name_binding());
|
||||
let _ = parent.try_define_child(name, ns, self.new_name_binding(def.to_name_binding()));
|
||||
}
|
||||
|
||||
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
|
||||
/// otherwise, reports an error.
|
||||
fn define<T: ToNameBinding<'b>>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) {
|
||||
let binding = def.to_name_binding();
|
||||
let old_binding = match parent.try_define_child(name, ns, binding.clone()) {
|
||||
Some(old_binding) => old_binding,
|
||||
None => return,
|
||||
let binding = self.new_name_binding(def.to_name_binding());
|
||||
let old_binding = match parent.try_define_child(name, ns, binding) {
|
||||
Ok(()) => return,
|
||||
Err(old_binding) => old_binding,
|
||||
};
|
||||
|
||||
let span = binding.span.unwrap_or(DUMMY_SP);
|
||||
|
@ -699,18 +698,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||
debug!("(building import directive) building import directive: {}::{}",
|
||||
names_to_string(&module_.imports.borrow().last().unwrap().module_path),
|
||||
target);
|
||||
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
for &ns in [TypeNS, ValueNS].iter() {
|
||||
let mut resolution = import_resolutions.entry((target, ns)).or_insert(
|
||||
ImportResolution::new(id, is_public)
|
||||
);
|
||||
|
||||
resolution.outstanding_references += 1;
|
||||
// the source of this name is different now
|
||||
resolution.id = id;
|
||||
resolution.is_public = is_public;
|
||||
}
|
||||
module_.increment_outstanding_references_for(target, ValueNS);
|
||||
module_.increment_outstanding_references_for(target, TypeNS);
|
||||
}
|
||||
GlobImport => {
|
||||
// Set the glob flag. This tells us that we don't know the
|
||||
|
|
|
@ -87,13 +87,12 @@ use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt};
|
|||
use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr};
|
||||
use rustc_front::util::walk_pat;
|
||||
|
||||
use std::collections::{hash_map, HashMap, HashSet};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
use std::mem::replace;
|
||||
|
||||
use resolve_imports::{Target, ImportDirective, ImportResolution};
|
||||
use resolve_imports::Shadowable;
|
||||
use resolve_imports::{ImportDirective, NameResolution};
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
|
@ -343,12 +342,10 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
|
|||
if let Some(sp) = resolver.ast_map.span_if_local(did) {
|
||||
err.span_note(sp, "constant defined here");
|
||||
}
|
||||
if let Some(directive) = resolver.current_module
|
||||
.import_resolutions
|
||||
.borrow()
|
||||
.get(&(name, ValueNS)) {
|
||||
let item = resolver.ast_map.expect_item(directive.id);
|
||||
err.span_note(item.span, "constant imported here");
|
||||
if let Success(binding) = resolver.current_module.resolve_name(name, ValueNS, true) {
|
||||
if binding.is_import() {
|
||||
err.span_note(binding.span.unwrap(), "constant imported here");
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
@ -653,10 +650,10 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
type ErrorMessage = Option<(Span, String)>;
|
||||
pub type ErrorMessage = Option<(Span, String)>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
enum ResolveResult<T> {
|
||||
pub enum ResolveResult<T> {
|
||||
Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
|
||||
Indeterminate, // Couldn't determine due to unresolved globs.
|
||||
Success(T), // Successfully resolved the import.
|
||||
|
@ -670,6 +667,13 @@ impl<T> ResolveResult<T> {
|
|||
Success(t) => f(t),
|
||||
}
|
||||
}
|
||||
|
||||
fn success(self) -> Option<T> {
|
||||
match self {
|
||||
Success(t) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FallbackSuggestion {
|
||||
|
@ -795,7 +799,7 @@ pub struct ModuleS<'a> {
|
|||
is_public: bool,
|
||||
is_extern_crate: bool,
|
||||
|
||||
children: RefCell<HashMap<(Name, Namespace), NameBinding<'a>>>,
|
||||
children: RefCell<HashMap<(Name, Namespace), NameResolution<'a>>>,
|
||||
imports: RefCell<Vec<ImportDirective>>,
|
||||
|
||||
// The anonymous children of this node. Anonymous children are pseudo-
|
||||
|
@ -814,8 +818,7 @@ pub struct ModuleS<'a> {
|
|||
// entry block for `f`.
|
||||
anonymous_children: RefCell<NodeMap<Module<'a>>>,
|
||||
|
||||
// The status of resolving each import in this module.
|
||||
import_resolutions: RefCell<HashMap<(Name, Namespace), ImportResolution<'a>>>,
|
||||
shadowed_traits: RefCell<Vec<&'a NameBinding<'a>>>,
|
||||
|
||||
// The number of unresolved globs that this module exports.
|
||||
glob_count: Cell<usize>,
|
||||
|
@ -847,7 +850,7 @@ impl<'a> ModuleS<'a> {
|
|||
children: RefCell::new(HashMap::new()),
|
||||
imports: RefCell::new(Vec::new()),
|
||||
anonymous_children: RefCell::new(NodeMap()),
|
||||
import_resolutions: RefCell::new(HashMap::new()),
|
||||
shadowed_traits: RefCell::new(Vec::new()),
|
||||
glob_count: Cell::new(0),
|
||||
pub_count: Cell::new(0),
|
||||
pub_glob_count: Cell::new(0),
|
||||
|
@ -856,26 +859,60 @@ impl<'a> ModuleS<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_child(&self, name: Name, ns: Namespace) -> Option<NameBinding<'a>> {
|
||||
self.children.borrow().get(&(name, ns)).cloned()
|
||||
fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool)
|
||||
-> ResolveResult<&'a NameBinding<'a>> {
|
||||
let glob_count =
|
||||
if allow_private_imports { self.glob_count.get() } else { self.pub_glob_count.get() };
|
||||
|
||||
self.children.borrow().get(&(name, ns)).cloned().unwrap_or_default().result(glob_count)
|
||||
.and_then(|binding| {
|
||||
let allowed = allow_private_imports || !binding.is_import() || binding.is_public();
|
||||
if allowed { Success(binding) } else { Failed(None) }
|
||||
})
|
||||
}
|
||||
|
||||
// If the name is not yet defined, define the name and return None.
|
||||
// Otherwise, return the existing definition.
|
||||
fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>)
|
||||
-> Option<NameBinding<'a>> {
|
||||
match self.children.borrow_mut().entry((name, ns)) {
|
||||
hash_map::Entry::Vacant(entry) => { entry.insert(binding); None }
|
||||
hash_map::Entry::Occupied(entry) => { Some(entry.get().clone()) },
|
||||
}
|
||||
}
|
||||
// Define the name or return the existing binding if there is a collision.
|
||||
fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>)
|
||||
-> Result<(), &'a NameBinding<'a>> {
|
||||
let mut children = self.children.borrow_mut();
|
||||
let resolution = children.entry((name, ns)).or_insert_with(Default::default);
|
||||
|
||||
fn for_each_local_child<F: FnMut(Name, Namespace, &NameBinding<'a>)>(&self, mut f: F) {
|
||||
for (&(name, ns), name_binding) in self.children.borrow().iter() {
|
||||
if !name_binding.is_extern_crate() {
|
||||
f(name, ns, name_binding)
|
||||
// FIXME #31379: We can use methods from imported traits shadowed by non-import items
|
||||
if let Some(old_binding) = resolution.binding {
|
||||
if !old_binding.is_import() && binding.is_import() {
|
||||
if let Some(Def::Trait(_)) = binding.def() {
|
||||
self.shadowed_traits.borrow_mut().push(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolution.try_define(binding)
|
||||
}
|
||||
|
||||
fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) {
|
||||
let mut children = self.children.borrow_mut();
|
||||
children.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1;
|
||||
}
|
||||
|
||||
fn decrement_outstanding_references_for(&self, name: Name, ns: Namespace) {
|
||||
match self.children.borrow_mut().get_mut(&(name, ns)).unwrap().outstanding_references {
|
||||
0 => panic!("No more outstanding references!"),
|
||||
ref mut outstanding_references => { *outstanding_references -= 1; }
|
||||
}
|
||||
}
|
||||
|
||||
fn for_each_child<F: FnMut(Name, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
|
||||
for (&(name, ns), name_resolution) in self.children.borrow().iter() {
|
||||
name_resolution.binding.map(|binding| f(name, ns, binding));
|
||||
}
|
||||
}
|
||||
|
||||
fn for_each_local_child<F: FnMut(Name, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
|
||||
self.for_each_child(|name, ns, name_binding| {
|
||||
if !name_binding.is_import() && !name_binding.is_extern_crate() {
|
||||
f(name, ns, name_binding)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn def_id(&self) -> Option<DefId> {
|
||||
|
@ -951,21 +988,27 @@ bitflags! {
|
|||
// Variants are considered `PUBLIC`, but some of them live in private enums.
|
||||
// We need to track them to prohibit reexports like `pub use PrivEnum::Variant`.
|
||||
const PRIVATE_VARIANT = 1 << 2,
|
||||
const PRELUDE = 1 << 3,
|
||||
const GLOB_IMPORTED = 1 << 4,
|
||||
}
|
||||
}
|
||||
|
||||
// Records a possibly-private value, type, or module definition.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct NameBinding<'a> {
|
||||
modifiers: DefModifiers, // see note in ImportResolution about how to use this
|
||||
def_or_module: DefOrModule<'a>,
|
||||
modifiers: DefModifiers,
|
||||
kind: NameBindingKind<'a>,
|
||||
span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum DefOrModule<'a> {
|
||||
#[derive(Debug)]
|
||||
enum NameBindingKind<'a> {
|
||||
Def(Def),
|
||||
Module(Module<'a>),
|
||||
Import {
|
||||
binding: &'a NameBinding<'a>,
|
||||
id: NodeId,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> NameBinding<'a> {
|
||||
|
@ -976,20 +1019,22 @@ impl<'a> NameBinding<'a> {
|
|||
DefModifiers::empty()
|
||||
} | DefModifiers::IMPORTABLE;
|
||||
|
||||
NameBinding { modifiers: modifiers, def_or_module: DefOrModule::Module(module), span: span }
|
||||
NameBinding { modifiers: modifiers, kind: NameBindingKind::Module(module), span: span }
|
||||
}
|
||||
|
||||
fn module(&self) -> Option<Module<'a>> {
|
||||
match self.def_or_module {
|
||||
DefOrModule::Module(ref module) => Some(module),
|
||||
DefOrModule::Def(_) => None,
|
||||
match self.kind {
|
||||
NameBindingKind::Module(module) => Some(module),
|
||||
NameBindingKind::Def(_) => None,
|
||||
NameBindingKind::Import { binding, .. } => binding.module(),
|
||||
}
|
||||
}
|
||||
|
||||
fn def(&self) -> Option<Def> {
|
||||
match self.def_or_module {
|
||||
DefOrModule::Def(def) => Some(def),
|
||||
DefOrModule::Module(ref module) => module.def,
|
||||
match self.kind {
|
||||
NameBindingKind::Def(def) => Some(def),
|
||||
NameBindingKind::Module(module) => module.def,
|
||||
NameBindingKind::Import { binding, .. } => binding.def(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1009,6 +1054,13 @@ impl<'a> NameBinding<'a> {
|
|||
fn is_extern_crate(&self) -> bool {
|
||||
self.module().map(|module| module.is_extern_crate).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_import(&self) -> bool {
|
||||
match self.kind {
|
||||
NameBindingKind::Import { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interns the names of the primitive types.
|
||||
|
@ -1112,6 +1164,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
|
|||
|
||||
pub struct ResolverArenas<'a> {
|
||||
modules: arena::TypedArena<ModuleS<'a>>,
|
||||
name_bindings: arena::TypedArena<NameBinding<'a>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -1177,6 +1230,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
fn arenas() -> ResolverArenas<'a> {
|
||||
ResolverArenas {
|
||||
modules: arena::TypedArena::new(),
|
||||
name_bindings: arena::TypedArena::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1188,6 +1242,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
|
||||
}
|
||||
|
||||
fn new_name_binding(&self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> {
|
||||
self.arenas.name_bindings.alloc(name_binding)
|
||||
}
|
||||
|
||||
fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def) -> Module<'a> {
|
||||
let mut module = ModuleS::new(parent_link, Some(def), false, true);
|
||||
module.is_extern_crate = true;
|
||||
|
@ -1199,14 +1257,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn record_import_use(&mut self, name: Name, ns: Namespace, resolution: &ImportResolution<'a>) {
|
||||
let import_id = resolution.id;
|
||||
self.used_imports.insert((import_id, ns));
|
||||
match resolution.target.as_ref().and_then(|target| target.target_module.def_id()) {
|
||||
Some(DefId { krate, .. }) => { self.used_crates.insert(krate); }
|
||||
_ => {}
|
||||
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
|
||||
// track extern crates for unused_extern_crate lint
|
||||
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
|
||||
self.used_crates.insert(krate);
|
||||
}
|
||||
|
||||
let import_id = match binding.kind {
|
||||
NameBindingKind::Import { id, .. } => id,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
self.used_imports.insert((import_id, ns));
|
||||
|
||||
if !self.make_glob_map {
|
||||
return;
|
||||
}
|
||||
|
@ -1237,8 +1300,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
lp: LastPrivate)
|
||||
-> ResolveResult<(Module<'a>, LastPrivate)> {
|
||||
fn search_parent_externals<'a>(needle: Name, module: Module<'a>) -> Option<Module<'a>> {
|
||||
match module.get_child(needle, TypeNS) {
|
||||
Some(ref binding) if binding.is_extern_crate() => Some(module),
|
||||
match module.resolve_name(needle, TypeNS, false) {
|
||||
Success(binding) if binding.is_extern_crate() => Some(module),
|
||||
_ => match module.parent_link {
|
||||
ModuleParentLink(ref parent, _) => {
|
||||
search_parent_externals(needle, parent)
|
||||
|
@ -1295,20 +1358,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
name);
|
||||
return Indeterminate;
|
||||
}
|
||||
Success((target, used_proxy)) => {
|
||||
Success(binding) => {
|
||||
// Check to see whether there are type bindings, and, if
|
||||
// so, whether there is a module within.
|
||||
if let Some(module_def) = target.binding.module() {
|
||||
// track extern crates for unused_extern_crate lint
|
||||
if let Some(did) = module_def.def_id() {
|
||||
self.used_crates.insert(did.krate);
|
||||
}
|
||||
|
||||
if let Some(module_def) = binding.module() {
|
||||
search_module = module_def;
|
||||
|
||||
// Keep track of the closest private module used
|
||||
// when resolving this import chain.
|
||||
if !used_proxy && !search_module.is_public {
|
||||
if !binding.is_public() {
|
||||
if let Some(did) = search_module.def_id() {
|
||||
closest_private = LastMod(DependsOn(did));
|
||||
}
|
||||
|
@ -1399,7 +1457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
debug!("(resolving module path for import) indeterminate; bailing");
|
||||
return Indeterminate;
|
||||
}
|
||||
Success((target, _)) => match target.binding.module() {
|
||||
Success(binding) => match binding.module() {
|
||||
Some(containing_module) => {
|
||||
search_module = containing_module;
|
||||
start_index = 1;
|
||||
|
@ -1433,7 +1491,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
name: Name,
|
||||
namespace: Namespace,
|
||||
record_used: bool)
|
||||
-> ResolveResult<(Target<'a>, bool)> {
|
||||
-> ResolveResult<&'a NameBinding<'a>> {
|
||||
debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
|
||||
name,
|
||||
namespace,
|
||||
|
@ -1455,10 +1513,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
debug!("(resolving item in lexical scope) indeterminate higher scope; bailing");
|
||||
return Indeterminate;
|
||||
}
|
||||
Success((target, used_reexport)) => {
|
||||
Success(binding) => {
|
||||
// We found the module.
|
||||
debug!("(resolving item in lexical scope) found name in module, done");
|
||||
return Success((target, used_reexport));
|
||||
return Success(binding);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1552,51 +1610,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Attempts to resolve the supplied name in the given module for the
|
||||
/// given namespace. If successful, returns the target corresponding to
|
||||
/// given namespace. If successful, returns the binding corresponding to
|
||||
/// the name.
|
||||
///
|
||||
/// The boolean returned on success is an indicator of whether this lookup
|
||||
/// passed through a public re-export proxy.
|
||||
fn resolve_name_in_module(&mut self,
|
||||
module_: Module<'a>,
|
||||
module: Module<'a>,
|
||||
name: Name,
|
||||
namespace: Namespace,
|
||||
allow_private_imports: bool,
|
||||
record_used: bool)
|
||||
-> ResolveResult<(Target<'a>, bool)> {
|
||||
debug!("(resolving name in module) resolving `{}` in `{}`",
|
||||
name,
|
||||
module_to_string(&*module_));
|
||||
-> ResolveResult<&'a NameBinding<'a>> {
|
||||
debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module));
|
||||
|
||||
// First, check the direct children of the module.
|
||||
build_reduced_graph::populate_module_if_necessary(self, module_);
|
||||
|
||||
if let Some(binding) = module_.get_child(name, namespace) {
|
||||
debug!("(resolving name in module) found node as child");
|
||||
return Success((Target::new(module_, binding, Shadowable::Never), false));
|
||||
}
|
||||
|
||||
// Check the list of resolved imports.
|
||||
match module_.import_resolutions.borrow().get(&(name, namespace)) {
|
||||
Some(import_resolution) if allow_private_imports || import_resolution.is_public => {
|
||||
if import_resolution.is_public && import_resolution.outstanding_references != 0 {
|
||||
debug!("(resolving name in module) import unresolved; bailing out");
|
||||
return Indeterminate;
|
||||
}
|
||||
if let Some(target) = import_resolution.target.clone() {
|
||||
debug!("(resolving name in module) resolved to import");
|
||||
if record_used {
|
||||
self.record_import_use(name, namespace, &import_resolution);
|
||||
}
|
||||
return Success((target, true));
|
||||
}
|
||||
build_reduced_graph::populate_module_if_necessary(self, module);
|
||||
module.resolve_name(name, namespace, allow_private_imports).and_then(|binding| {
|
||||
if record_used {
|
||||
self.record_use(name, namespace, binding);
|
||||
}
|
||||
Some(..) | None => {} // Continue.
|
||||
}
|
||||
|
||||
// We're out of luck.
|
||||
debug!("(resolving name in module) failed to resolve `{}`", name);
|
||||
return Failed(None);
|
||||
Success(binding)
|
||||
})
|
||||
}
|
||||
|
||||
fn report_unresolved_imports(&mut self, module_: Module<'a>) {
|
||||
|
@ -1659,22 +1690,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
Some(name) => {
|
||||
build_reduced_graph::populate_module_if_necessary(self, &orig_module);
|
||||
|
||||
match orig_module.get_child(name, TypeNS) {
|
||||
None => {
|
||||
debug!("!!! (with scope) didn't find `{}` in `{}`",
|
||||
name,
|
||||
module_to_string(&*orig_module));
|
||||
}
|
||||
Some(name_binding) => {
|
||||
match name_binding.module() {
|
||||
None => {
|
||||
debug!("!!! (with scope) didn't find module for `{}` in `{}`",
|
||||
name,
|
||||
module_to_string(&*orig_module));
|
||||
}
|
||||
Some(module_) => {
|
||||
self.current_module = module_;
|
||||
}
|
||||
if let Success(name_binding) = orig_module.resolve_name(name, TypeNS, false) {
|
||||
match name_binding.module() {
|
||||
None => {
|
||||
debug!("!!! (with scope) didn't find module for `{}` in `{}`",
|
||||
name,
|
||||
module_to_string(orig_module));
|
||||
}
|
||||
Some(module) => {
|
||||
self.current_module = module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2619,11 +2643,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
-> BareIdentifierPatternResolution {
|
||||
let module = self.current_module;
|
||||
match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
|
||||
Success((target, _)) => {
|
||||
Success(binding) => {
|
||||
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
|
||||
name,
|
||||
&target.binding);
|
||||
match target.binding.def() {
|
||||
binding);
|
||||
match binding.def() {
|
||||
None => {
|
||||
panic!("resolved name in the value namespace to a set of name bindings \
|
||||
with no def?!");
|
||||
|
@ -2779,7 +2803,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let module = self.current_module;
|
||||
let name = identifier.unhygienic_name;
|
||||
match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
|
||||
Success((target, _)) => target.binding.def().map(LocalDef::from_def),
|
||||
Success(binding) => binding.def().map(LocalDef::from_def),
|
||||
Failed(Some((span, msg))) => {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&*msg));
|
||||
None
|
||||
|
@ -2917,15 +2941,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let name = segments.last().unwrap().identifier.name;
|
||||
let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
|
||||
let def = match result {
|
||||
Success((Target { binding, .. }, _)) => {
|
||||
Success(binding) => {
|
||||
let (def, lp) = binding.def_and_lp();
|
||||
(def, last_private.or(lp))
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(DefId{krate: kid, ..}) = containing_module.def_id() {
|
||||
self.used_crates.insert(kid);
|
||||
}
|
||||
return Some(def);
|
||||
}
|
||||
|
||||
|
@ -2976,7 +2997,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
let name = segments.last().unwrap().identifier.name;
|
||||
match self.resolve_name_in_module(containing_module, name, namespace, false, true) {
|
||||
Success((Target { binding, .. }, _)) => {
|
||||
Success(binding) => {
|
||||
let (def, lp) = binding.def_and_lp();
|
||||
Some((def, last_private.or(lp)))
|
||||
}
|
||||
|
@ -3014,12 +3035,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if let AnonymousModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
|
||||
if let Success((target, _)) = self.resolve_name_in_module(module,
|
||||
ident.unhygienic_name,
|
||||
namespace,
|
||||
true,
|
||||
true) {
|
||||
if let Some(def) = target.binding.def() {
|
||||
if let Success(binding) = self.resolve_name_in_module(module,
|
||||
ident.unhygienic_name,
|
||||
namespace,
|
||||
true,
|
||||
true) {
|
||||
if let Some(def) = binding.def() {
|
||||
return Some(LocalDef::from_def(def));
|
||||
}
|
||||
}
|
||||
|
@ -3063,8 +3084,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
if name_path.len() == 1 {
|
||||
match this.primitive_type_table.primitive_types.get(last_name) {
|
||||
Some(_) => None,
|
||||
None => this.current_module.get_child(*last_name, TypeNS)
|
||||
.as_ref()
|
||||
None => this.current_module.resolve_name(*last_name, TypeNS, true).success()
|
||||
.and_then(NameBinding::module)
|
||||
}
|
||||
} else {
|
||||
|
@ -3124,7 +3144,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
// Look for a method in the current self type's impl module.
|
||||
if let Some(module) = get_module(self, path.span, &name_path) {
|
||||
if let Some(binding) = module.get_child(name, ValueNS) {
|
||||
if let Success(binding) = module.resolve_name(name, ValueNS, true) {
|
||||
if let Some(Def::Method(did)) = binding.def() {
|
||||
if is_static_method(self, did) {
|
||||
return StaticMethod(path_names_to_string(&path, 0));
|
||||
|
@ -3447,32 +3467,26 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// Look for trait children.
|
||||
build_reduced_graph::populate_module_if_necessary(self, &search_module);
|
||||
|
||||
for (&(_, ns), name_binding) in search_module.children.borrow().iter() {
|
||||
if ns != TypeNS { continue }
|
||||
search_module.for_each_child(|_, ns, name_binding| {
|
||||
if ns != TypeNS { return }
|
||||
let trait_def_id = match name_binding.def() {
|
||||
Some(Def::Trait(trait_def_id)) => trait_def_id,
|
||||
Some(..) | None => continue,
|
||||
Some(..) | None => return,
|
||||
};
|
||||
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
|
||||
add_trait_info(&mut found_traits, trait_def_id, name);
|
||||
let trait_name = self.get_trait_name(trait_def_id);
|
||||
self.record_use(trait_name, TypeNS, name_binding);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Look for imports.
|
||||
for (&(_, ns), import) in search_module.import_resolutions.borrow().iter() {
|
||||
if ns != TypeNS { continue }
|
||||
let target = match import.target {
|
||||
Some(ref target) => target,
|
||||
None => continue,
|
||||
};
|
||||
let did = match target.binding.def() {
|
||||
Some(Def::Trait(trait_def_id)) => trait_def_id,
|
||||
Some(..) | None => continue,
|
||||
};
|
||||
// Look for shadowed traits.
|
||||
for binding in search_module.shadowed_traits.borrow().iter() {
|
||||
let did = binding.def().unwrap().def_id();
|
||||
if self.trait_item_map.contains_key(&(name, did)) {
|
||||
add_trait_info(&mut found_traits, did, name);
|
||||
let trait_name = self.get_trait_name(did);
|
||||
self.record_import_use(trait_name, TypeNS, &import);
|
||||
self.record_use(trait_name, TypeNS, binding);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,9 @@
|
|||
use self::ImportDirectiveSubclass::*;
|
||||
|
||||
use DefModifiers;
|
||||
use DefOrModule;
|
||||
use Module;
|
||||
use Namespace::{self, TypeNS, ValueNS};
|
||||
use NameBinding;
|
||||
use {NameBinding, NameBindingKind};
|
||||
use ResolveResult;
|
||||
use ResolveResult::*;
|
||||
use Resolver;
|
||||
|
@ -26,7 +25,6 @@ use build_reduced_graph;
|
|||
|
||||
use rustc::lint;
|
||||
use rustc::middle::def::*;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::privacy::*;
|
||||
|
||||
use syntax::ast::{NodeId, Name};
|
||||
|
@ -78,66 +76,74 @@ impl ImportDirective {
|
|||
shadowable: shadowable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The item that an import resolves to.
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct Target<'a> {
|
||||
pub target_module: Module<'a>,
|
||||
pub binding: NameBinding<'a>,
|
||||
pub shadowable: Shadowable,
|
||||
}
|
||||
// Given the binding to which this directive resolves in a particular namespace,
|
||||
// this returns the binding for the name this directive defines in that namespace.
|
||||
fn import<'a>(&self, binding: &'a NameBinding<'a>) -> NameBinding<'a> {
|
||||
let mut modifiers = match self.is_public {
|
||||
true => DefModifiers::PUBLIC | DefModifiers::IMPORTABLE,
|
||||
false => DefModifiers::empty(),
|
||||
};
|
||||
if let GlobImport = self.subclass {
|
||||
modifiers = modifiers | DefModifiers::GLOB_IMPORTED;
|
||||
}
|
||||
if self.shadowable == Shadowable::Always {
|
||||
modifiers = modifiers | DefModifiers::PRELUDE;
|
||||
}
|
||||
|
||||
impl<'a> Target<'a> {
|
||||
pub fn new(target_module: Module<'a>, binding: NameBinding<'a>, shadowable: Shadowable)
|
||||
-> Self {
|
||||
Target {
|
||||
target_module: target_module,
|
||||
binding: binding,
|
||||
shadowable: shadowable,
|
||||
NameBinding {
|
||||
kind: NameBindingKind::Import { binding: binding, id: self.id },
|
||||
span: Some(self.span),
|
||||
modifiers: modifiers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// An ImportResolution records what we know about an imported name in a given namespace.
|
||||
/// More specifically, it records the number of unresolved `use` directives that import the name,
|
||||
/// the `use` directive importing the name in the namespace, and the `NameBinding` to which the
|
||||
/// name in the namespace resolves (if applicable).
|
||||
/// Different `use` directives may import the same name in different namespaces.
|
||||
pub struct ImportResolution<'a> {
|
||||
// When outstanding_references reaches zero, outside modules can count on the targets being
|
||||
// correct. Before then, all bets are off; future `use` directives could override the name.
|
||||
// Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
|
||||
// is if the name is imported by exactly two `use` directives, one of which resolves to a
|
||||
// value and the other of which resolves to a type.
|
||||
#[derive(Clone, Default)]
|
||||
/// Records information about the resolution of a name in a module.
|
||||
pub struct NameResolution<'a> {
|
||||
/// The number of unresolved single imports that could define the name.
|
||||
pub outstanding_references: usize,
|
||||
|
||||
/// Whether this resolution came from a `use` or a `pub use`.
|
||||
pub is_public: bool,
|
||||
|
||||
/// Resolution of the name in the namespace
|
||||
pub target: Option<Target<'a>>,
|
||||
|
||||
/// The source node of the `use` directive
|
||||
pub id: NodeId,
|
||||
/// The least shadowable known binding for this name, or None if there are no known bindings.
|
||||
pub binding: Option<&'a NameBinding<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> ImportResolution<'a> {
|
||||
pub fn new(id: NodeId, is_public: bool) -> Self {
|
||||
ImportResolution {
|
||||
outstanding_references: 0,
|
||||
id: id,
|
||||
target: None,
|
||||
is_public: is_public,
|
||||
impl<'a> NameResolution<'a> {
|
||||
pub fn result(&self, outstanding_globs: usize) -> ResolveResult<&'a NameBinding<'a>> {
|
||||
// If no unresolved imports (single or glob) can define the name, self.binding is final.
|
||||
if self.outstanding_references == 0 && outstanding_globs == 0 {
|
||||
return self.binding.map(Success).unwrap_or(Failed(None));
|
||||
}
|
||||
|
||||
if let Some(binding) = self.binding {
|
||||
// Single imports will never be shadowable by other single or glob imports.
|
||||
if !binding.defined_with(DefModifiers::GLOB_IMPORTED) { return Success(binding); }
|
||||
// Non-PRELUDE glob imports will never be shadowable by other glob imports.
|
||||
if self.outstanding_references == 0 && !binding.defined_with(DefModifiers::PRELUDE) {
|
||||
return Success(binding);
|
||||
}
|
||||
}
|
||||
|
||||
Indeterminate
|
||||
}
|
||||
|
||||
pub fn shadowable(&self) -> Shadowable {
|
||||
match self.target {
|
||||
Some(ref target) => target.shadowable,
|
||||
None => Shadowable::Always,
|
||||
// Define the name or return the existing binding if there is a collision.
|
||||
pub fn try_define(&mut self, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> {
|
||||
let is_prelude = |binding: &NameBinding| binding.defined_with(DefModifiers::PRELUDE);
|
||||
let old_binding = match self.binding {
|
||||
Some(_) if is_prelude(binding) => return Ok(()),
|
||||
Some(old_binding) if !is_prelude(old_binding) => old_binding,
|
||||
_ => { self.binding = Some(binding); return Ok(()); }
|
||||
};
|
||||
|
||||
// FIXME #31337: We currently allow items to shadow glob-imported re-exports.
|
||||
if !old_binding.is_import() && binding.defined_with(DefModifiers::GLOB_IMPORTED) {
|
||||
if let NameBindingKind::Import { binding, .. } = binding.kind {
|
||||
if binding.is_import() { return Ok(()); }
|
||||
}
|
||||
}
|
||||
|
||||
Err(old_binding)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,38 +209,18 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
|
||||
/// Resolves an `ImportResolvingError` into the correct enum discriminant
|
||||
/// and passes that on to `resolve_error`.
|
||||
fn import_resolving_error(&self, e: ImportResolvingError) {
|
||||
fn import_resolving_error(&self, e: ImportResolvingError<'b>) {
|
||||
// If it's a single failed import then create a "fake" import
|
||||
// resolution for it so that later resolve stages won't complain.
|
||||
if let SingleImport(target, _) = e.import_directive.subclass {
|
||||
let mut import_resolutions = e.source_module.import_resolutions.borrow_mut();
|
||||
|
||||
let resolution = import_resolutions.entry((target, ValueNS)).or_insert_with(|| {
|
||||
debug!("(resolving import error) adding import resolution for `{}`",
|
||||
target);
|
||||
|
||||
ImportResolution::new(e.import_directive.id,
|
||||
e.import_directive.is_public)
|
||||
let dummy_binding = self.resolver.new_name_binding(NameBinding {
|
||||
modifiers: DefModifiers::PRELUDE,
|
||||
kind: NameBindingKind::Def(Def::Err),
|
||||
span: None,
|
||||
});
|
||||
|
||||
if resolution.target.is_none() {
|
||||
debug!("(resolving import error) adding fake target to import resolution of `{}`",
|
||||
target);
|
||||
|
||||
let name_binding = NameBinding {
|
||||
modifiers: DefModifiers::IMPORTABLE,
|
||||
def_or_module: DefOrModule::Def(Def::Err),
|
||||
span: None,
|
||||
};
|
||||
|
||||
// Create a fake target pointing to a fake name binding in our
|
||||
// own module
|
||||
let target = Target::new(e.source_module,
|
||||
name_binding,
|
||||
Shadowable::Always);
|
||||
|
||||
resolution.target = Some(target);
|
||||
}
|
||||
let _ = e.source_module.try_define_child(target, ValueNS, dummy_binding);
|
||||
let _ = e.source_module.try_define_child(target, TypeNS, dummy_binding);
|
||||
}
|
||||
|
||||
let path = import_path_to_string(&e.import_directive.module_path,
|
||||
|
@ -373,70 +359,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Resolves the name in the namespace of the module because it is being imported by
|
||||
/// importing_module. Returns the module in which the name was defined (as opposed to imported),
|
||||
/// the name bindings defining the name, and whether or not the name was imported into `module`.
|
||||
fn resolve_name_in_module(&mut self,
|
||||
module: Module<'b>, // Module containing the name
|
||||
name: Name,
|
||||
ns: Namespace,
|
||||
importing_module: Module<'b>) // Module importing the name
|
||||
-> (ResolveResult<(Module<'b>, NameBinding<'b>)>, bool) {
|
||||
build_reduced_graph::populate_module_if_necessary(self.resolver, module);
|
||||
if let Some(name_binding) = module.get_child(name, ns) {
|
||||
if name_binding.is_extern_crate() {
|
||||
// track the extern crate as used.
|
||||
if let Some(DefId { krate, .. }) = name_binding.module().unwrap().def_id() {
|
||||
self.resolver.used_crates.insert(krate);
|
||||
}
|
||||
}
|
||||
return (Success((module, name_binding)), false)
|
||||
}
|
||||
|
||||
// If there is an unresolved glob at this point in the containing module, bail out.
|
||||
// We don't know enough to be able to resolve the name.
|
||||
if module.pub_glob_count.get() > 0 {
|
||||
return (Indeterminate, false);
|
||||
}
|
||||
|
||||
match module.import_resolutions.borrow().get(&(name, ns)) {
|
||||
// The containing module definitely doesn't have an exported import with the
|
||||
// name in question. We can therefore accurately report that names are unbound.
|
||||
None => (Failed(None), false),
|
||||
|
||||
// The name is an import which has been fully resolved, so we just follow it.
|
||||
Some(resolution) if resolution.outstanding_references == 0 => {
|
||||
// Import resolutions must be declared with "pub" in order to be exported.
|
||||
if !resolution.is_public {
|
||||
return (Failed(None), false);
|
||||
}
|
||||
|
||||
let target = resolution.target.clone();
|
||||
if let Some(Target { target_module, binding, shadowable: _ }) = target {
|
||||
self.resolver.record_import_use(name, ns, &resolution);
|
||||
(Success((target_module, binding)), true)
|
||||
} else {
|
||||
(Failed(None), false)
|
||||
}
|
||||
}
|
||||
|
||||
// If module is the same module whose import we are resolving and
|
||||
// it has an unresolved import with the same name as `name`, then the user
|
||||
// is actually trying to import an item that is declared in the same scope
|
||||
//
|
||||
// e.g
|
||||
// use self::submodule;
|
||||
// pub mod submodule;
|
||||
//
|
||||
// In this case we continue as if we resolved the import and let
|
||||
// check_for_conflicts_between_imports_and_items handle the conflict
|
||||
Some(_) => match (importing_module.def_id(), module.def_id()) {
|
||||
(Some(id1), Some(id2)) if id1 == id2 => (Failed(None), false),
|
||||
_ => (Indeterminate, false)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_single_import(&mut self,
|
||||
module_: Module<'b>,
|
||||
target_module: Module<'b>,
|
||||
|
@ -463,16 +385,28 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// If this is a circular import, we temporarily count it as determined so that
|
||||
// it fails (as opposed to being indeterminate) when nothing else can define it.
|
||||
if target_module.def_id() == module_.def_id() && source == target {
|
||||
module_.decrement_outstanding_references_for(target, ValueNS);
|
||||
module_.decrement_outstanding_references_for(target, TypeNS);
|
||||
}
|
||||
|
||||
// We need to resolve both namespaces for this to succeed.
|
||||
let (value_result, value_used_reexport) =
|
||||
self.resolve_name_in_module(target_module, source, ValueNS, module_);
|
||||
let (type_result, type_used_reexport) =
|
||||
self.resolve_name_in_module(target_module, source, TypeNS, module_);
|
||||
let value_result =
|
||||
self.resolver.resolve_name_in_module(target_module, source, ValueNS, false, true);
|
||||
let type_result =
|
||||
self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true);
|
||||
|
||||
if target_module.def_id() == module_.def_id() && source == target {
|
||||
module_.increment_outstanding_references_for(target, ValueNS);
|
||||
module_.increment_outstanding_references_for(target, TypeNS);
|
||||
}
|
||||
|
||||
match (&value_result, &type_result) {
|
||||
(&Success((_, ref name_binding)), _) if !value_used_reexport &&
|
||||
directive.is_public &&
|
||||
!name_binding.is_public() => {
|
||||
(&Success(name_binding), _) if !name_binding.is_import() &&
|
||||
directive.is_public &&
|
||||
!name_binding.is_public() => {
|
||||
let msg = format!("`{}` is private, and cannot be reexported", source);
|
||||
let note_msg = format!("Consider marking `{}` as `pub` in the imported module",
|
||||
source);
|
||||
|
@ -481,8 +415,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
.emit();
|
||||
}
|
||||
|
||||
(_, &Success((_, ref name_binding))) if !type_used_reexport &&
|
||||
directive.is_public => {
|
||||
(_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => {
|
||||
if !name_binding.is_public() {
|
||||
let msg = format!("`{}` is private, and cannot be reexported", source);
|
||||
let note_msg =
|
||||
|
@ -504,120 +437,47 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
let mut lev_suggestion = "".to_owned();
|
||||
match (&value_result, &type_result) {
|
||||
(&Indeterminate, _) | (_, &Indeterminate) => return Indeterminate,
|
||||
(&Failed(_), &Failed(_)) => {
|
||||
let children = target_module.children.borrow();
|
||||
let names = children.keys().map(|&(ref name, _)| name);
|
||||
if let Some(name) = find_best_match_for_name(names, &source.as_str(), None) {
|
||||
lev_suggestion = format!(". Did you mean to use `{}`?", name);
|
||||
} else {
|
||||
let resolutions = target_module.import_resolutions.borrow();
|
||||
let names = resolutions.keys().map(|&(ref name, _)| name);
|
||||
if let Some(name) = find_best_match_for_name(names,
|
||||
&source.as_str(),
|
||||
None) {
|
||||
lev_suggestion =
|
||||
format!(". Did you mean to use the re-exported import `{}`?", name);
|
||||
}
|
||||
}
|
||||
let lev_suggestion = match find_best_match_for_name(names, &source.as_str(), None) {
|
||||
Some(name) => format!(". Did you mean to use `{}`?", name),
|
||||
None => "".to_owned(),
|
||||
};
|
||||
let msg = format!("There is no `{}` in `{}`{}",
|
||||
source,
|
||||
module_to_string(target_module), lev_suggestion);
|
||||
return Failed(Some((directive.span, msg)));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let mut value_used_public = false;
|
||||
let mut type_used_public = false;
|
||||
|
||||
// We've successfully resolved the import. Write the results in.
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
|
||||
{
|
||||
let mut check_and_write_import = |namespace, result, used_public: &mut bool| {
|
||||
let result: &ResolveResult<(Module<'b>, NameBinding)> = result;
|
||||
|
||||
let import_resolution = import_resolutions.get_mut(&(target, namespace)).unwrap();
|
||||
let namespace_name = match namespace {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
};
|
||||
|
||||
match *result {
|
||||
Success((ref target_module, ref name_binding)) => {
|
||||
debug!("(resolving single import) found {:?} target: {:?}",
|
||||
namespace_name,
|
||||
name_binding.def());
|
||||
self.check_for_conflicting_import(&import_resolution,
|
||||
directive.span,
|
||||
target,
|
||||
namespace);
|
||||
|
||||
self.check_that_import_is_importable(&name_binding,
|
||||
directive.span,
|
||||
target);
|
||||
|
||||
import_resolution.target = Some(Target::new(target_module,
|
||||
name_binding.clone(),
|
||||
directive.shadowable));
|
||||
import_resolution.id = directive.id;
|
||||
import_resolution.is_public = directive.is_public;
|
||||
|
||||
self.add_export(module_, target, &import_resolution);
|
||||
*used_public = name_binding.is_public();
|
||||
}
|
||||
Failed(_) => {
|
||||
// Continue.
|
||||
}
|
||||
Indeterminate => {
|
||||
panic!("{:?} result should be known at this point", namespace_name);
|
||||
}
|
||||
for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] {
|
||||
if let Success(binding) = *result {
|
||||
if !binding.defined_with(DefModifiers::IMPORTABLE) {
|
||||
let msg = format!("`{}` is not directly importable", target);
|
||||
span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
|
||||
}
|
||||
|
||||
self.check_for_conflicts_between_imports_and_items(module_,
|
||||
import_resolution,
|
||||
directive.span,
|
||||
(target, namespace));
|
||||
};
|
||||
check_and_write_import(ValueNS, &value_result, &mut value_used_public);
|
||||
check_and_write_import(TypeNS, &type_result, &mut type_used_public);
|
||||
self.define(module_, target, ns, directive.import(binding));
|
||||
}
|
||||
}
|
||||
|
||||
if let (&Failed(_), &Failed(_)) = (&value_result, &type_result) {
|
||||
let msg = format!("There is no `{}` in `{}`{}",
|
||||
source,
|
||||
module_to_string(target_module), lev_suggestion);
|
||||
return Failed(Some((directive.span, msg)));
|
||||
}
|
||||
// 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.
|
||||
module_.decrement_outstanding_references_for(target, ValueNS);
|
||||
module_.decrement_outstanding_references_for(target, TypeNS);
|
||||
|
||||
let value_used_public = value_used_reexport || value_used_public;
|
||||
let type_used_public = type_used_reexport || type_used_public;
|
||||
|
||||
let value_def_and_priv = {
|
||||
let import_resolution_value = import_resolutions.get_mut(&(target, ValueNS)).unwrap();
|
||||
assert!(import_resolution_value.outstanding_references >= 1);
|
||||
import_resolution_value.outstanding_references -= 1;
|
||||
|
||||
// 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.
|
||||
import_resolution_value.target.as_ref().map(|target| {
|
||||
let def = target.binding.def().unwrap();
|
||||
let last_private = if value_used_public { lp } else { DependsOn(def.def_id()) };
|
||||
(def, last_private)
|
||||
})
|
||||
};
|
||||
|
||||
let type_def_and_priv = {
|
||||
let import_resolution_type = import_resolutions.get_mut(&(target, TypeNS)).unwrap();
|
||||
assert!(import_resolution_type.outstanding_references >= 1);
|
||||
import_resolution_type.outstanding_references -= 1;
|
||||
|
||||
import_resolution_type.target.as_ref().map(|target| {
|
||||
let def = target.binding.def().unwrap();
|
||||
let last_private = if type_used_public { lp } else { DependsOn(def.def_id()) };
|
||||
(def, last_private)
|
||||
})
|
||||
let def_and_priv = |binding: &NameBinding| {
|
||||
let def = binding.def().unwrap();
|
||||
let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) };
|
||||
(def, last_private)
|
||||
};
|
||||
let value_def_and_priv = value_result.success().map(&def_and_priv);
|
||||
let type_def_and_priv = type_result.success().map(&def_and_priv);
|
||||
|
||||
let import_lp = LastImport {
|
||||
value_priv: value_def_and_priv.map(|(_, p)| p),
|
||||
|
@ -626,22 +486,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
type_used: Used,
|
||||
};
|
||||
|
||||
if let Some((def, _)) = value_def_and_priv {
|
||||
self.resolver.def_map.borrow_mut().insert(directive.id,
|
||||
PathResolution {
|
||||
base_def: def,
|
||||
last_private: import_lp,
|
||||
depth: 0,
|
||||
});
|
||||
}
|
||||
if let Some((def, _)) = type_def_and_priv {
|
||||
self.resolver.def_map.borrow_mut().insert(directive.id,
|
||||
PathResolution {
|
||||
base_def: def,
|
||||
last_private: import_lp,
|
||||
depth: 0,
|
||||
});
|
||||
}
|
||||
let write_path_resolution = |(def, _)| {
|
||||
let path_resolution =
|
||||
PathResolution { base_def: def, last_private: import_lp, depth: 0 };
|
||||
self.resolver.def_map.borrow_mut().insert(directive.id, path_resolution);
|
||||
};
|
||||
value_def_and_priv.map(&write_path_resolution);
|
||||
type_def_and_priv.map(&write_path_resolution);
|
||||
|
||||
debug!("(resolving single import) successfully resolved import");
|
||||
return Success(());
|
||||
|
@ -654,76 +505,41 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
fn resolve_glob_import(&mut self,
|
||||
module_: Module<'b>,
|
||||
target_module: Module<'b>,
|
||||
import_directive: &ImportDirective,
|
||||
directive: &ImportDirective,
|
||||
lp: LastPrivate)
|
||||
-> ResolveResult<()> {
|
||||
let id = import_directive.id;
|
||||
let is_public = import_directive.is_public;
|
||||
|
||||
// This function works in a highly imperative manner; it eagerly adds
|
||||
// everything it can to the list of import resolutions of the module
|
||||
// node.
|
||||
debug!("(resolving glob import) resolving glob import {}", id);
|
||||
|
||||
// We must bail out if the node has unresolved imports of any kind
|
||||
// (including globs).
|
||||
if (*target_module).pub_count.get() > 0 {
|
||||
// We must bail out if the node has unresolved imports of any kind (including globs).
|
||||
if target_module.pub_count.get() > 0 {
|
||||
debug!("(resolving glob import) target module has unresolved pub imports; bailing out");
|
||||
return ResolveResult::Indeterminate;
|
||||
return Indeterminate;
|
||||
}
|
||||
|
||||
// Add all resolved imports from the containing module.
|
||||
let import_resolutions = target_module.import_resolutions.borrow();
|
||||
|
||||
if module_.import_resolutions.borrow_state() != ::std::cell::BorrowState::Unused {
|
||||
// In this case, target_module == module_
|
||||
// This means we are trying to glob import a module into itself,
|
||||
// and it is a no-go
|
||||
debug!("(resolving glob imports) target module is current module; giving up");
|
||||
return ResolveResult::Failed(Some((import_directive.span,
|
||||
"Cannot glob-import a module into itself.".into())));
|
||||
}
|
||||
|
||||
for (&(name, ns), target_import_resolution) in import_resolutions.iter() {
|
||||
debug!("(resolving glob import) writing module resolution {} into `{}`",
|
||||
name,
|
||||
module_to_string(module_));
|
||||
|
||||
// Here we merge two import resolutions.
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
let mut dest_import_resolution =
|
||||
import_resolutions.entry((name, ns))
|
||||
.or_insert_with(|| ImportResolution::new(id, is_public));
|
||||
|
||||
match target_import_resolution.target {
|
||||
Some(ref target) if target_import_resolution.is_public => {
|
||||
self.check_for_conflicting_import(&dest_import_resolution,
|
||||
import_directive.span,
|
||||
name,
|
||||
ns);
|
||||
dest_import_resolution.id = id;
|
||||
dest_import_resolution.is_public = is_public;
|
||||
dest_import_resolution.target = Some(target.clone());
|
||||
self.add_export(module_, name, &dest_import_resolution);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if module_.def_id() == target_module.def_id() {
|
||||
// This means we are trying to glob import a module into itself, and it is a no-go
|
||||
let msg = "Cannot glob-import a module into itself.".into();
|
||||
return Failed(Some((directive.span, msg)));
|
||||
}
|
||||
|
||||
// Add all children from the containing module.
|
||||
build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
|
||||
target_module.for_each_child(|name, ns, binding| {
|
||||
if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return }
|
||||
self.define(module_, name, ns, directive.import(binding));
|
||||
|
||||
target_module.for_each_local_child(|name, ns, name_binding| {
|
||||
self.merge_import_resolution(module_,
|
||||
target_module,
|
||||
import_directive,
|
||||
(name, ns),
|
||||
name_binding.clone());
|
||||
if ns == TypeNS && directive.is_public &&
|
||||
binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
let msg = format!("variant `{}` is private, and cannot be reexported (error \
|
||||
E0364), consider declaring its enum as `pub`", name);
|
||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
directive.id,
|
||||
directive.span,
|
||||
msg);
|
||||
}
|
||||
});
|
||||
|
||||
// Record the destination of this import
|
||||
if let Some(did) = target_module.def_id() {
|
||||
self.resolver.def_map.borrow_mut().insert(id,
|
||||
self.resolver.def_map.borrow_mut().insert(directive.id,
|
||||
PathResolution {
|
||||
base_def: Def::Mod(did),
|
||||
last_private: lp,
|
||||
|
@ -732,196 +548,77 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
debug!("(resolving glob import) successfully resolved import");
|
||||
return ResolveResult::Success(());
|
||||
return Success(());
|
||||
}
|
||||
|
||||
fn merge_import_resolution(&mut self,
|
||||
module_: Module<'b>,
|
||||
containing_module: Module<'b>,
|
||||
import_directive: &ImportDirective,
|
||||
(name, ns): (Name, Namespace),
|
||||
name_binding: NameBinding<'b>) {
|
||||
let id = import_directive.id;
|
||||
let is_public = import_directive.is_public;
|
||||
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
let dest_import_resolution = import_resolutions.entry((name, ns)).or_insert_with(|| {
|
||||
ImportResolution::new(id, is_public)
|
||||
});
|
||||
|
||||
debug!("(resolving glob import) writing resolution `{}` in `{}` to `{}`",
|
||||
name,
|
||||
module_to_string(&*containing_module),
|
||||
module_to_string(module_));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
|
||||
|
||||
if ns == TypeNS && is_public && name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
let msg = format!("variant `{}` is private, and cannot be reexported (error \
|
||||
E0364), consider declaring its enum as `pub`", name);
|
||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
import_directive.id,
|
||||
import_directive.span,
|
||||
msg);
|
||||
fn define(&mut self,
|
||||
parent: Module<'b>,
|
||||
name: Name,
|
||||
ns: Namespace,
|
||||
binding: NameBinding<'b>) {
|
||||
let binding = self.resolver.new_name_binding(binding);
|
||||
if let Err(old_binding) = parent.try_define_child(name, ns, binding) {
|
||||
self.report_conflict(name, ns, binding, old_binding);
|
||||
} else if binding.is_public() { // Add to the export map
|
||||
if let (Some(parent_def_id), Some(def)) = (parent.def_id(), binding.def()) {
|
||||
let parent_node_id = self.resolver.ast_map.as_local_node_id(parent_def_id).unwrap();
|
||||
let export = Export { name: name, def_id: def.def_id() };
|
||||
self.resolver.export_map.entry(parent_node_id).or_insert(Vec::new()).push(export);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name_binding.defined_with(modifier) {
|
||||
let namespace_name = match ns {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
fn report_conflict(&mut self,
|
||||
name: Name,
|
||||
ns: Namespace,
|
||||
binding: &'b NameBinding<'b>,
|
||||
old_binding: &'b NameBinding<'b>) {
|
||||
if old_binding.is_extern_crate() {
|
||||
let msg = format!("import `{0}` conflicts with imported crate \
|
||||
in this module (maybe you meant `use {0}::*`?)",
|
||||
name);
|
||||
span_err!(self.resolver.session, binding.span.unwrap(), E0254, "{}", &msg);
|
||||
} else if old_binding.is_import() {
|
||||
let ns_word = match (ns, old_binding.module()) {
|
||||
(ValueNS, _) => "value",
|
||||
(TypeNS, Some(module)) if module.is_normal() => "module",
|
||||
(TypeNS, Some(module)) if module.is_trait() => "trait",
|
||||
(TypeNS, _) => "type",
|
||||
};
|
||||
debug!("(resolving glob import) ... for {} target", namespace_name);
|
||||
if dest_import_resolution.shadowable() == Shadowable::Never {
|
||||
let msg = format!("a {} named `{}` has already been imported in this module",
|
||||
namespace_name,
|
||||
name);
|
||||
span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
|
||||
} else {
|
||||
let target = Target::new(containing_module,
|
||||
name_binding.clone(),
|
||||
import_directive.shadowable);
|
||||
dest_import_resolution.target = Some(target);
|
||||
dest_import_resolution.id = id;
|
||||
dest_import_resolution.is_public = is_public;
|
||||
self.add_export(module_, name, &dest_import_resolution);
|
||||
}
|
||||
}
|
||||
|
||||
self.check_for_conflicts_between_imports_and_items(module_,
|
||||
dest_import_resolution,
|
||||
import_directive.span,
|
||||
(name, ns));
|
||||
}
|
||||
|
||||
fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportResolution<'b>) {
|
||||
if !resolution.is_public { return }
|
||||
let node_id = match module.def_id() {
|
||||
Some(def_id) => self.resolver.ast_map.as_local_node_id(def_id).unwrap(),
|
||||
None => return,
|
||||
};
|
||||
let export = match resolution.target.as_ref().unwrap().binding.def() {
|
||||
Some(def) => Export { name: name, def_id: def.def_id() },
|
||||
None => return,
|
||||
};
|
||||
self.resolver.export_map.entry(node_id).or_insert(Vec::new()).push(export);
|
||||
}
|
||||
|
||||
/// Checks that imported names and items don't have the same name.
|
||||
fn check_for_conflicting_import(&mut self,
|
||||
import_resolution: &ImportResolution,
|
||||
import_span: Span,
|
||||
name: Name,
|
||||
namespace: Namespace) {
|
||||
let target = &import_resolution.target;
|
||||
debug!("check_for_conflicting_import: {}; target exists: {}",
|
||||
name,
|
||||
target.is_some());
|
||||
|
||||
match *target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
let ns_word = match namespace {
|
||||
TypeNS => {
|
||||
match target.binding.module() {
|
||||
Some(ref module) if module.is_normal() => "module",
|
||||
Some(ref module) if module.is_trait() => "trait",
|
||||
_ => "type",
|
||||
}
|
||||
}
|
||||
ValueNS => "value",
|
||||
};
|
||||
let use_id = import_resolution.id;
|
||||
let item = self.resolver.ast_map.expect_item(use_id);
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0252,
|
||||
"a {} named `{}` has already been imported \
|
||||
in this module",
|
||||
ns_word,
|
||||
name);
|
||||
span_note!(&mut err,
|
||||
item.span,
|
||||
"previous import of `{}` here",
|
||||
name);
|
||||
err.emit();
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that an import is actually importable
|
||||
fn check_that_import_is_importable(&mut self,
|
||||
name_binding: &NameBinding,
|
||||
import_span: Span,
|
||||
name: Name) {
|
||||
if !name_binding.defined_with(DefModifiers::IMPORTABLE) {
|
||||
let msg = format!("`{}` is not directly importable", name);
|
||||
span_err!(self.resolver.session, import_span, E0253, "{}", &msg[..]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that imported names and items don't have the same name.
|
||||
fn check_for_conflicts_between_imports_and_items(&mut self,
|
||||
module: Module<'b>,
|
||||
import: &ImportResolution<'b>,
|
||||
import_span: Span,
|
||||
(name, ns): (Name, Namespace)) {
|
||||
// Check for item conflicts.
|
||||
let name_binding = match module.get_child(name, ns) {
|
||||
None => {
|
||||
// There can't be any conflicts.
|
||||
return;
|
||||
}
|
||||
Some(name_binding) => name_binding,
|
||||
};
|
||||
|
||||
if ns == ValueNS {
|
||||
match import.target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0255,
|
||||
"import `{}` conflicts with \
|
||||
value in this module",
|
||||
name);
|
||||
if let Some(span) = name_binding.span {
|
||||
err.span_note(span, "conflicting value here");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
} else {
|
||||
match import.target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
if name_binding.is_extern_crate() {
|
||||
let msg = format!("import `{0}` conflicts with imported crate \
|
||||
in this module (maybe you meant `use {0}::*`?)",
|
||||
name);
|
||||
span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
|
||||
return;
|
||||
}
|
||||
|
||||
let (what, note) = match name_binding.module() {
|
||||
Some(ref module) if module.is_normal() =>
|
||||
("existing submodule", "note conflicting module here"),
|
||||
Some(ref module) if module.is_trait() =>
|
||||
("trait in this module", "note conflicting trait here"),
|
||||
_ => ("type in this module", "note conflicting type here"),
|
||||
};
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
import_span,
|
||||
E0256,
|
||||
"import `{}` conflicts with {}",
|
||||
name,
|
||||
what);
|
||||
if let Some(span) = name_binding.span {
|
||||
err.span_note(span, note);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
binding.span.unwrap(),
|
||||
E0252,
|
||||
"a {} named `{}` has already been imported \
|
||||
in this module",
|
||||
ns_word,
|
||||
name);
|
||||
err.span_note(old_binding.span.unwrap(),
|
||||
&format!("previous import of `{}` here", name));
|
||||
err.emit();
|
||||
} else if ns == ValueNS { // Check for item conflicts in the value namespace
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
binding.span.unwrap(),
|
||||
E0255,
|
||||
"import `{}` conflicts with value in this module",
|
||||
name);
|
||||
err.span_note(old_binding.span.unwrap(), "conflicting value here");
|
||||
err.emit();
|
||||
} else { // Check for item conflicts in the type namespace
|
||||
let (what, note) = match old_binding.module() {
|
||||
Some(ref module) if module.is_normal() =>
|
||||
("existing submodule", "note conflicting module here"),
|
||||
Some(ref module) if module.is_trait() =>
|
||||
("trait in this module", "note conflicting trait here"),
|
||||
_ => ("type in this module", "note conflicting type here"),
|
||||
};
|
||||
let mut err = struct_span_err!(self.resolver.session,
|
||||
binding.span.unwrap(),
|
||||
E0256,
|
||||
"import `{}` conflicts with {}",
|
||||
name,
|
||||
what);
|
||||
err.span_note(old_binding.span.unwrap(), note);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,5 @@ mod foo {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let _ = foo::X; //~ ERROR unresolved name `foo::X`
|
||||
let _ = foo::X;
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ use foo::bar; //~ ERROR unresolved import `foo::bar`. Maybe a missing `extern cr
|
|||
|
||||
use bar::Baz as x; //~ ERROR unresolved import `bar::Baz`. There is no `Baz` in `bar`. Did you mean to use `Bar`?
|
||||
|
||||
use food::baz; //~ ERROR unresolved import `food::baz`. There is no `baz` in `food`. Did you mean to use the re-exported import `bag`?
|
||||
use food::baz; //~ ERROR unresolved import `food::baz`. There is no `baz` in `food`. Did you mean to use `bag`?
|
||||
|
||||
use food::{beens as Foo}; //~ ERROR unresolved import `food::beens`. There is no `beens` in `food`. Did you mean to use the re-exported import `beans`?
|
||||
use food::{beens as Foo}; //~ ERROR unresolved import `food::beens`. There is no `beens` in `food`. Did you mean to use `beans`?
|
||||
|
||||
mod bar {
|
||||
pub struct Bar;
|
||||
|
|
Loading…
Reference in New Issue