Avoid cascading name resolution errors caused by an ambiguous module.

This commit is contained in:
Jeffrey Seyfried 2016-08-22 07:12:13 +00:00
parent 32a0cfeb48
commit 4f5616e3c4
3 changed files with 45 additions and 30 deletions

View file

@ -749,10 +749,6 @@ impl<'a> LexicalScopeBinding<'a> {
_ => None,
}
}
fn module(self) -> Option<Module<'a>> {
self.item().and_then(NameBinding::module)
}
}
/// The link from a module up to its nearest parent node.
@ -884,12 +880,13 @@ enum NameBindingKind<'a> {
struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
impl<'a> NameBinding<'a> {
fn module(&self) -> Option<Module<'a>> {
fn module(&self) -> Result<Module<'a>, bool /* true if an error has already been reported */> {
match self.kind {
NameBindingKind::Module(module) => Some(module),
NameBindingKind::Def(_) => None,
NameBindingKind::Module(module) => Ok(module),
NameBindingKind::Import { binding, .. } => binding.module(),
NameBindingKind::Ambiguity { .. } => None,
NameBindingKind::Def(Def::Err) => Err(true),
NameBindingKind::Def(_) => Err(false),
NameBindingKind::Ambiguity { .. } => Err(false),
}
}
@ -915,7 +912,7 @@ impl<'a> NameBinding<'a> {
}
fn is_extern_crate(&self) -> bool {
self.module().and_then(|module| module.extern_crate_id).is_some()
self.module().ok().and_then(|module| module.extern_crate_id).is_some()
}
fn is_import(&self) -> bool {
@ -1269,7 +1266,7 @@ impl<'a> Resolver<'a> {
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
-> bool /* true if an error was reported */ {
// track extern crates for unused_extern_crate lint
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
if let Some(DefId { krate, .. }) = binding.module().ok().and_then(ModuleS::def_id) {
self.used_crates.insert(krate);
}
@ -1292,6 +1289,18 @@ impl<'a> Resolver<'a> {
}
}
fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option<Span>)
-> ResolveResult<Module<'a>> {
match binding.module() {
Ok(module) => Success(module),
Err(true) => Failed(None),
Err(false) => {
let msg = format!("Not a module `{}`", name);
Failed(span.map(|span| (span, msg)))
}
}
}
/// Resolves the given module path from the given root `search_module`.
fn resolve_module_path_from_root(&mut self,
mut search_module: Module<'a>,
@ -1357,11 +1366,9 @@ impl<'a> Resolver<'a> {
Success(binding) => {
// Check to see whether there are type bindings, and, if
// so, whether there is a module within.
if let Some(module_def) = binding.module() {
search_module = module_def;
} else {
let msg = format!("Not a module `{}`", name);
return Failed(span.map(|span| (span, msg)));
match self.expect_module(name, binding, span) {
Success(module) => search_module = module,
result @ _ => return result,
}
}
}
@ -1414,17 +1421,20 @@ impl<'a> Resolver<'a> {
// first component of the path in the current lexical
// scope and then proceed to resolve below that.
let ident = ast::Ident::with_empty_ctxt(module_path[0]);
match self.resolve_ident_in_lexical_scope(ident, TypeNS, span)
.and_then(LexicalScopeBinding::module) {
None => {
let msg =
format!("Use of undeclared type or module `{}`", ident.name);
return Failed(span.map(|span| (span, msg)));
}
Some(containing_module) => {
search_module = containing_module;
start_index = 1;
let lexical_binding =
self.resolve_ident_in_lexical_scope(ident, TypeNS, span);
if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) {
match self.expect_module(ident.name, binding, span) {
Success(containing_module) => {
search_module = containing_module;
start_index = 1;
}
result @ _ => return result,
}
} else {
let msg =
format!("Use of undeclared type or module `{}`", ident.name);
return Failed(span.map(|span| (span, msg)));
}
}
}
@ -3202,7 +3212,7 @@ impl<'a> Resolver<'a> {
}
// collect submodules to explore
if let Some(module) = name_binding.module() {
if let Ok(module) = name_binding.module() {
// form the path
let path_segments = match module.parent_link {
NoParentLink => path_segments.clone(),
@ -3341,9 +3351,9 @@ impl<'a> Resolver<'a> {
let msg = {
let kind = match (ns, old_binding.module()) {
(ValueNS, _) => "a value",
(TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate",
(TypeNS, Some(module)) if module.is_normal() => "a module",
(TypeNS, Some(module)) if module.is_trait() => "a trait",
(TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate",
(TypeNS, Ok(module)) if module.is_normal() => "a module",
(TypeNS, Ok(module)) if module.is_trait() => "a trait",
(TypeNS, _) => "a type",
};
format!("{} named `{}` has already been {} in this {}",

View file

@ -460,7 +460,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
errors = true;
let (span, help) = match err {
Some((span, msg)) => (span, msg),
None => (import.span, String::new()),
None => continue,
};
// If the error is a single failed import then create a "fake" import

View file

@ -56,7 +56,12 @@ mod ambiguous_module_errors {
pub mod m2 { pub use super::m2 as foo; }
use self::m1::*; //~ NOTE
//~| NOTE
use self::m2::*; //~ NOTE
//~| NOTE
use self::foo::bar; //~ ERROR `foo` is ambiguous
//~| NOTE
fn f() {
foo::bar(); //~ ERROR `foo` is ambiguous