Replace children and import_resolutions with a single NameResolution-valued map.

Refactor away resolve_name_in_module in resolve_imports.rs

Rewrite and improve the core name resolution procedure in NameResolution::result and Module::resolve_name

Refactor the duplicate checking code into NameResolution::try_define
This commit is contained in:
Jeffrey Seyfried 2016-02-07 23:58:14 +00:00
parent d881eee608
commit 7000e70825
4 changed files with 223 additions and 501 deletions

View File

@ -87,7 +87,7 @@ 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;
@ -342,11 +342,8 @@ 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)) {
if let Some(binding) = directive.binding {
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");
}
}
@ -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.
@ -802,7 +799,7 @@ pub struct ModuleS<'a> {
is_public: bool,
is_extern_crate: bool,
children: RefCell<HashMap<(Name, Namespace), &'a NameBinding<'a>>>,
children: RefCell<HashMap<(Name, Namespace), NameResolution<'a>>>,
imports: RefCell<Vec<ImportDirective>>,
// The anonymous children of this node. Anonymous children are pseudo-
@ -821,9 +818,6 @@ 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), NameResolution<'a>>>,
// The number of unresolved globs that this module exports.
glob_count: Cell<usize>,
@ -854,7 +848,6 @@ 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()),
glob_count: Cell::new(0),
pub_count: Cell::new(0),
pub_glob_count: Cell::new(0),
@ -863,39 +856,49 @@ impl<'a> ModuleS<'a> {
}
}
fn get_child(&self, name: Name, ns: Namespace) -> Option<&'a 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.
// 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>> {
match self.children.borrow_mut().entry((name, ns)) {
hash_map::Entry::Vacant(entry) => { entry.insert(binding); Ok(()) }
hash_map::Entry::Occupied(entry) => { Err(entry.get()) },
}
self.children.borrow_mut().entry((name, ns)).or_insert_with(Default::default)
.try_define(binding)
}
fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) {
let mut resolutions = self.import_resolutions.borrow_mut();
resolutions.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1;
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.import_resolutions.borrow_mut().get_mut(&(name, ns)).unwrap()
.outstanding_references {
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) {
for (&(name, ns), name_binding) in self.children.borrow().iter() {
if !name_binding.is_extern_crate() {
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> {
@ -1240,7 +1243,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
#[inline]
fn record_import_use(&mut self, name: Name, ns: Namespace, binding: &NameBinding<'a>) {
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,
@ -1278,8 +1286,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(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)
@ -1591,53 +1599,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// given namespace. If successful, returns the binding corresponding to
/// the name.
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<&'a NameBinding<'a>> {
debug!("(resolving name in module) resolving `{}` in `{}`",
name,
module_to_string(&*module_));
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");
if binding.is_extern_crate() {
// track the extern crate as used.
if let Some(DefId { krate, .. }) = binding.module().unwrap().def_id() {
self.used_crates.insert(krate);
}
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);
}
return Success(binding);
}
// Check the list of resolved imports.
match module_.import_resolutions.borrow().get(&(name, namespace)) {
Some(import_resolution) => {
if let Some(binding) = import_resolution.binding {
if !allow_private_imports && binding.is_public() { return Failed(None) }
if binding.is_public() && import_resolution.outstanding_references != 0 {
debug!("(resolving name in module) import unresolved; bailing out");
return Indeterminate;
}
debug!("(resolving name in module) resolved to import");
if record_used {
self.record_import_use(name, namespace, binding);
}
return Success(binding);
}
}
None => {}
}
// 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>) {
@ -1700,22 +1676,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;
}
}
}
@ -3101,7 +3070,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)
None => this.current_module.resolve_name(*last_name, TypeNS, true).success()
.and_then(NameBinding::module)
}
} else {
@ -3161,7 +3130,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));
@ -3484,34 +3453,18 @@ 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 binding = match import.binding {
Some(binding) => binding,
None => continue,
};
let did = match binding.def() {
Some(Def::Trait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
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, binding);
}
}
});
match search_module.parent_link {
NoParentLink | ModuleParentLink(..) => break,

View File

@ -25,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};
@ -100,21 +99,12 @@ impl ImportDirective {
}
}
#[derive(Debug)]
/// An NameResolution 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.
#[derive(Clone, Copy)]
/// Records information about the resolution of a name in a module.
pub struct NameResolution<'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.
/// The number of unresolved single imports that could define the name.
pub outstanding_references: usize,
/// Resolution of the name in the namespace
/// The least shadowable known binding for this name, or None if there are no known bindings.
pub binding: Option<&'a NameBinding<'a>>,
}
@ -125,13 +115,41 @@ impl<'a> Default for NameResolution<'a> {
}
impl<'a> NameResolution<'a> {
pub fn shadowable(&self) -> Shadowable {
match self.binding {
Some(binding) if binding.defined_with(DefModifiers::PRELUDE) =>
Shadowable::Always,
Some(_) => Shadowable::Never,
None => Shadowable::Always,
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
}
// 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(old_binding) if is_prelude(binding) && !is_prelude(old_binding) => return Ok(()),
Some(old_binding) if is_prelude(old_binding) == is_prelude(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)
}
}
@ -201,27 +219,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
// 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);
NameResolution::default()
let dummy_binding = self.resolver.new_name_binding(NameBinding {
modifiers: DefModifiers::PRELUDE,
kind: NameBindingKind::Def(Def::Err),
span: None,
});
if resolution.binding.is_none() {
debug!("(resolving import error) adding fake target to import resolution of `{}`",
target);
let dummy_binding = self.resolver.new_name_binding(NameBinding {
modifiers: DefModifiers::IMPORTABLE,
kind: NameBindingKind::Def(Def::Err),
span: None,
});
resolution.binding = Some(dummy_binding);
}
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,
@ -360,68 +365,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 name bindings defining the name.
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<&'b NameBinding<'b>> {
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(name_binding);
}
// 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;
}
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),
// The name is an import which has been fully resolved, so we just follow it.
Some(resolution) if resolution.outstanding_references == 0 => {
if let Some(binding) = resolution.binding {
// Import resolutions must be declared with "pub" in order to be exported.
if !binding.is_public() {
return Failed(None);
}
self.resolver.record_import_use(name, ns, binding);
Success(binding)
} else {
Failed(None)
}
}
// 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),
_ => Indeterminate
},
}
}
fn resolve_single_import(&mut self,
module_: Module<'b>,
target_module: Module<'b>,
@ -448,11 +391,23 @@ 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 =
self.resolve_name_in_module(target_module, source, ValueNS, module_);
self.resolver.resolve_name_in_module(target_module, source, ValueNS, false, true);
let type_result =
self.resolve_name_in_module(target_module, source, TypeNS, module_);
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(name_binding), _) if !name_binding.is_import() &&
@ -488,82 +443,32 @@ 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)));
}
_ => (),
}
// 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| {
let result: &ResolveResult<&NameBinding> = result;
let import_resolution = import_resolutions.get_mut(&(target, namespace)).unwrap();
let namespace_name = match namespace {
TypeNS => "type",
ValueNS => "value",
};
match *result {
Success(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.binding =
Some(self.resolver.new_name_binding(directive.import(name_binding)));
self.add_export(module_, target, import_resolution.binding.unwrap());
}
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);
check_and_write_import(TypeNS, &type_result);
}
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_def_and_priv = {
@ -624,74 +529,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;
// 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(|| NameResolution::default());
match target_import_resolution.binding {
Some(binding) if binding.is_public() => {
self.check_for_conflicting_import(&dest_import_resolution,
import_directive.span,
name,
ns);
dest_import_resolution.binding =
Some(self.resolver.new_name_binding(import_directive.import(binding)));
self.add_export(module_, name, dest_import_resolution.binding.unwrap());
}
_ => {}
}
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);
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,
@ -700,61 +572,7 @@ 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: &'b NameBinding<'b>) {
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(|| {
NameResolution::default()
});
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 {
dest_import_resolution.binding =
Some(self.resolver.new_name_binding(import_directive.import(name_binding)));
self.add_export(module_, name, dest_import_resolution.binding.unwrap());
}
}
self.check_for_conflicts_between_imports_and_items(module_,
dest_import_resolution,
import_directive.span,
(name, ns));
return Success(());
}
fn add_export(&mut self, module: Module<'b>, name: Name, binding: &NameBinding<'b>) {
@ -770,119 +588,70 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
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: &NameResolution,
import_span: Span,
name: Name,
namespace: Namespace) {
let binding = &import_resolution.binding;
debug!("check_for_conflicting_import: {}; target exists: {}",
name,
binding.is_some());
match *binding {
Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
let ns_word = match namespace {
TypeNS => {
match binding.module() {
Some(ref module) if module.is_normal() => "module",
Some(ref module) if module.is_trait() => "trait",
_ => "type",
}
}
ValueNS => "value",
};
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,
binding.span.unwrap(),
"previous import of `{}` here",
name);
err.emit();
}
Some(_) | None => {}
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() {
self.add_export(parent, name, binding);
}
}
/// 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: &NameResolution<'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.binding {
Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
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.binding {
Some(binding) if !binding.defined_with(DefModifiers::PRELUDE) => {
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();
}
}
}

View File

@ -20,5 +20,5 @@ mod foo {
}
fn main() {
let _ = foo::X; //~ ERROR unresolved name `foo::X`
let _ = foo::X;
}

View File

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