]> git.lizzy.rs Git - rust.git/commitdiff
Avoid cascading name resolution errors caused by an ambiguous module.
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Mon, 22 Aug 2016 07:12:13 +0000 (07:12 +0000)
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Thu, 1 Sep 2016 22:30:29 +0000 (22:30 +0000)
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/test/compile-fail/imports/duplicate.rs

index a881feaa4d35351641dae6de547f24e46d7f18a5..0fe7f9ed21547d5f022cee680220e2c418cfd0ed 100644 (file)
@@ -749,10 +749,6 @@ fn item(self) -> Option<&'a NameBinding<'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 @@ fn is_variant(&self) -> bool {
     }
 
     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 @@ fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'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 @@ fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
         }
     }
 
+    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 @@ fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Mo
                 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 @@ fn resolve_module_path(&mut self,
                         // 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 @@ fn lookup_candidates<FilterFn>(&mut self,
                 }
 
                 // 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 @@ fn report_conflict(&self,
         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 {}",
index cb89231fc055155aa8bd7a312f225d70dc9d72cb..c8982d95d4e0084320db43e57589d64a4d76ada4 100644 (file)
@@ -460,7 +460,7 @@ fn resolve_imports(&mut self) {
                 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
index 70936b254464665dc6b781572a3dcd1113c307da..fb61bb8e489bec7b3e9ccb80f251ea8fcc423f29 100644 (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