diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6bc73194aa98b..775ed34ab073c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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(&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>(&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 diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 054aa1d5f555b..5fbe06a868f07 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 { +pub enum ResolveResult { 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 ResolveResult { Success(t) => f(t), } } + + fn success(self) -> Option { + 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>>, + children: RefCell>>, imports: RefCell>, // 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>>, - // The status of resolving each import in this module. - import_resolutions: RefCell>>, + shadowed_traits: RefCell>>, // The number of unresolved globs that this module exports. glob_count: Cell, @@ -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> { - 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) } + }) + } + + // 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); + + // 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; } - // 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> { - 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()) }, + 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_local_child)>(&self, mut f: F) { - for (&(name, ns), name_binding) in self.children.borrow().iter() { - if !name_binding.is_extern_crate() { + fn for_each_child)>(&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)>(&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 { @@ -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, } -#[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> { - 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 { - 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>, + name_bindings: arena::TypedArena>, } #[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> { - 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); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 3d2300e44c468..6667e48987087 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -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>, - - /// 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); - } - - 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))); + self.define(module_, target, ns, directive.import(binding)); + } } - 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; + // 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); - 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; - } - - // 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()))); + return Indeterminate; } - 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_local_child(|name, ns, name_binding| { - self.merge_import_resolution(module_, - target_module, - import_directive, - (name, ns), - name_binding.clone()); + 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)); + + 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(()); - } - - 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); - } - - if name_binding.defined_with(modifier) { - let namespace_name = match ns { - TypeNS => "type", - ValueNS => "value", - }; - 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); + return Success(()); } - /// 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(); + 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); } - 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 => {} - } + 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", + }; + 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(); } } } diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs index d6d7dbb4aecd8..923f95e69d122 100644 --- a/src/test/compile-fail/double-type-import.rs +++ b/src/test/compile-fail/double-type-import.rs @@ -20,5 +20,5 @@ mod foo { } fn main() { - let _ = foo::X; //~ ERROR unresolved name `foo::X` + let _ = foo::X; } diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index b6207450d9835..b60d19fcab4aa 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -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;