about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/diagnostics.rs12
-rw-r--r--src/librustc_resolve/lib.rs257
-rw-r--r--src/test/auxiliary/issue-21221-3.rs29
-rw-r--r--src/test/auxiliary/issue-21221-4.rs22
-rw-r--r--src/test/compile-fail/associated-types-eq-1.rs2
-rw-r--r--src/test/compile-fail/bad-type-env-capture.rs2
-rw-r--r--src/test/compile-fail/extern-with-type-bounds.rs2
-rw-r--r--src/test/compile-fail/glob-resolve1.rs6
-rw-r--r--src/test/compile-fail/inner-static-type-parameter.rs2
-rw-r--r--src/test/compile-fail/issue-18058.rs2
-rw-r--r--src/test/compile-fail/issue-18119.rs6
-rw-r--r--src/test/compile-fail/issue-19883.rs2
-rw-r--r--src/test/compile-fail/issue-21221-1.rs94
-rw-r--r--src/test/compile-fail/issue-21221-2.rs30
-rw-r--r--src/test/compile-fail/issue-21221-3.rs30
-rw-r--r--src/test/compile-fail/issue-21221-4.rs26
-rw-r--r--src/test/compile-fail/issue-22037.rs2
-rw-r--r--src/test/compile-fail/issue-22384.rs2
-rw-r--r--src/test/compile-fail/issue-3021-c.rs4
-rw-r--r--src/test/compile-fail/issue-3214.rs2
-rw-r--r--src/test/compile-fail/issue-4366-2.rs2
-rw-r--r--src/test/compile-fail/issue-5997-enum.rs2
-rw-r--r--src/test/compile-fail/issue-5997-struct.rs2
-rw-r--r--src/test/compile-fail/issue-7607-1.rs2
-rw-r--r--src/test/compile-fail/issue-8767.rs2
-rw-r--r--src/test/compile-fail/no-implicit-prelude-nested.rs30
-rw-r--r--src/test/compile-fail/no-implicit-prelude.rs10
-rw-r--r--src/test/compile-fail/privacy-ns1.rs4
-rw-r--r--src/test/compile-fail/resolve-type-param-in-item-in-trait.rs8
-rw-r--r--src/test/compile-fail/resolve-unknown-trait.rs6
-rw-r--r--src/test/compile-fail/trait-impl-for-module.rs2
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs2
32 files changed, 521 insertions, 85 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index dee2727c163..bfd8a6f1f61 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -461,12 +461,12 @@ impl Foo for Bar { // ok!
 "##,
 
 E0405: r##"
-An unknown trait was implemented. Example of erroneous code:
+The code refers to a trait that is not in scope. Example of erroneous code:
 
 ```compile_fail
 struct Foo;
 
-impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
+impl SomeTrait for Foo {} // error: trait `SomeTrait` is not in scope
 ```
 
 Please verify that the name of the trait wasn't misspelled and ensure that it
@@ -599,20 +599,20 @@ trait Baz : Foo + Foo2 {
 "##,
 
 E0412: r##"
-An undeclared type name was used. Example of erroneous codes:
+The type name used is not in scope. Example of erroneous codes:
 
 ```compile_fail
-impl Something {} // error: use of undeclared type name `Something`
+impl Something {} // error: type name `Something` is not in scope
 
 // or:
 
 trait Foo {
-    fn bar(N); // error: use of undeclared type name `N`
+    fn bar(N); // error: type name `N` is not in scope
 }
 
 // or:
 
-fn foo(x: T) {} // error: use of undeclared type name `T`
+fn foo(x: T) {} // type name `T` is not in scope
 ```
 
 To fix this error, please verify you didn't misspell the type name, you did
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 800d1bfe01b..0508a9ef729 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -81,6 +81,8 @@ use rustc_front::hir::{ItemFn, ItemForeignMod, ItemImpl, ItemMod, ItemStatic, It
 use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse};
 use rustc_front::hir::Local;
 use rustc_front::hir::{Pat, PatKind, Path, PrimTy};
+use rustc_front::hir::{PathSegment, PathParameters};
+use rustc_front::hir::HirVec;
 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;
@@ -117,6 +119,12 @@ enum SuggestionType {
     NotFound,
 }
 
+/// Candidates for a name resolution failure
+pub struct SuggestedCandidates {
+    name: String,
+    candidates: Vec<Path>,
+}
+
 pub enum ResolutionError<'a> {
     /// error E0401: can't use type parameters from outer function
     TypeParametersFromOuterFunction,
@@ -127,7 +135,7 @@ pub enum ResolutionError<'a> {
     /// error E0404: is not a trait
     IsNotATrait(&'a str),
     /// error E0405: use of undeclared trait name
-    UndeclaredTraitName(&'a str),
+    UndeclaredTraitName(&'a str, SuggestedCandidates),
     /// error E0406: undeclared associated type
     UndeclaredAssociatedType,
     /// error E0407: method is not a member of trait
@@ -145,7 +153,7 @@ pub enum ResolutionError<'a> {
     /// error E0411: use of `Self` outside of an impl or trait
     SelfUsedOutsideImplOrTrait,
     /// error E0412: use of undeclared
-    UseOfUndeclared(&'a str, &'a str),
+    UseOfUndeclared(&'a str, &'a str, SuggestedCandidates),
     /// error E0413: declaration shadows an enum variant or unit-like struct in scope
     DeclarationShadowsEnumVariantOrUnitLikeStruct(Name),
     /// error E0414: only irrefutable patterns allowed here
@@ -248,12 +256,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
         ResolutionError::IsNotATrait(name) => {
             struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name)
         }
-        ResolutionError::UndeclaredTraitName(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0405,
-                             "use of undeclared trait name `{}`",
-                             name)
+        ResolutionError::UndeclaredTraitName(name, candidates) => {
+            let mut err = struct_span_err!(resolver.session,
+                                           span,
+                                           E0405,
+                                           "trait `{}` is not in scope",
+                                           name);
+            show_candidates(&mut err, span, &candidates);
+            err
         }
         ResolutionError::UndeclaredAssociatedType => {
             struct_span_err!(resolver.session, span, E0406, "undeclared associated type")
@@ -313,13 +323,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                              E0411,
                              "use of `Self` outside of an impl or trait")
         }
-        ResolutionError::UseOfUndeclared(kind, name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0412,
-                             "use of undeclared {} `{}`",
-                             kind,
-                             name)
+        ResolutionError::UseOfUndeclared(kind, name, candidates) => {
+            let mut err = struct_span_err!(resolver.session,
+                                           span,
+                                           E0412,
+                                           "{} `{}` is undefined or not in scope",
+                                           kind,
+                                           name);
+            show_candidates(&mut err, span, &candidates);
+            err
         }
         ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => {
             struct_span_err!(resolver.session,
@@ -839,6 +851,7 @@ pub struct ModuleS<'a> {
 pub type Module<'a> = &'a ModuleS<'a>;
 
 impl<'a> ModuleS<'a> {
+
     fn new(parent_link: ParentLink<'a>, def: Option<Def>, external: bool, is_public: bool) -> Self {
         ModuleS {
             parent_link: parent_link,
@@ -1970,10 +1983,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Err(())
             }
         } else {
-            resolve_error(self,
-                          trait_path.span,
-                          ResolutionError::UndeclaredTraitName(&path_names_to_string(trait_path,
-                                                                                      path_depth)));
+
+            // find possible candidates
+            let trait_name = trait_path.segments.last().unwrap().identifier.name;
+            let candidates =
+                self.lookup_candidates(
+                    trait_name,
+                    TypeNS,
+                    |def| match def {
+                        Def::Trait(_) => true,
+                        _             => false,
+                    },
+                );
+
+            // create error object
+            let name = &path_names_to_string(trait_path, path_depth);
+            let error =
+                ResolutionError::UndeclaredTraitName(
+                    name,
+                    candidates,
+                );
+
+            resolve_error(self, trait_path.span, error);
             Err(())
         }
     }
@@ -2297,13 +2328,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                           ty.span,
                                           ResolutionError::SelfUsedOutsideImplOrTrait);
                         } else {
-                            resolve_error(self,
-                                          ty.span,
-                                          ResolutionError::UseOfUndeclared(
-                                                                    kind,
-                                                                    &path_names_to_string(path,
-                                                                                           0))
-                                         );
+                            let segment = path.segments.last();
+                            let segment = segment.expect("missing name in path");
+                            let type_name = segment.identifier.name;
+
+                            let candidates =
+                                self.lookup_candidates(
+                                    type_name,
+                                    TypeNS,
+                                    |def| match def {
+                                        Def::Trait(_) |
+                                        Def::Enum(_) |
+                                        Def::Struct(_) |
+                                        Def::TyAlias(_) => true,
+                                        _               => false,
+                                    },
+                                );
+
+                            // create error object
+                            let name = &path_names_to_string(path, 0);
+                            let error =
+                                ResolutionError::UseOfUndeclared(
+                                    kind,
+                                    name,
+                                    candidates,
+                                );
+
+                            resolve_error(self, ty.span, error);
                         }
                     }
                 }
@@ -3458,6 +3509,99 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         found_traits
     }
 
+    /// When name resolution fails, this method can be used to look up candidate
+    /// entities with the expected name. It allows filtering them using the
+    /// supplied predicate (which should be used to only accept the types of
+    /// definitions expected e.g. traits). The lookup spans across all crates.
+    ///
+    /// NOTE: The method does not look into imports, but this is not a problem,
+    /// since we report the definitions (thus, the de-aliased imports).
+    fn lookup_candidates<FilterFn>(&mut self,
+                                   lookup_name: Name,
+                                   namespace: Namespace,
+                                   filter_fn: FilterFn) -> SuggestedCandidates
+        where FilterFn: Fn(Def) -> bool {
+
+        let mut lookup_results = Vec::new();
+        let mut worklist = Vec::new();
+        worklist.push((self.graph_root, Vec::new(), false));
+
+        while let Some((in_module,
+                        path_segments,
+                        in_module_is_extern)) = worklist.pop() {
+            build_reduced_graph::populate_module_if_necessary(self, &in_module);
+
+            in_module.for_each_child(|name, ns, name_binding| {
+
+                // avoid imports entirely
+                if name_binding.is_import() { return; }
+
+                // collect results based on the filter function
+                if let Some(def) = name_binding.def() {
+                    if name == lookup_name && ns == namespace && filter_fn(def) {
+                        // create the path
+                        let ident = hir::Ident::from_name(name);
+                        let params = PathParameters::none();
+                        let segment = PathSegment {
+                            identifier: ident,
+                            parameters: params,
+                        };
+                        let span = name_binding.span.unwrap_or(syntax::codemap::DUMMY_SP);
+                        let mut segms = path_segments.clone();
+                        segms.push(segment);
+                        let segms = HirVec::from_vec(segms);
+                        let path = Path {
+                            span: span,
+                            global: true,
+                            segments: segms,
+                        };
+                        // the entity is accessible in the following cases:
+                        // 1. if it's defined in the same crate, it's always
+                        // accessible (since private entities can be made public)
+                        // 2. if it's defined in another crate, it's accessible
+                        // only if both the module is public and the entity is
+                        // declared as public (due to pruning, we don't explore
+                        // outside crate private modules => no need to check this)
+                        if !in_module_is_extern || name_binding.is_public() {
+                            lookup_results.push(path);
+                        }
+                    }
+                }
+
+                // collect submodules to explore
+                if let Some(module) = name_binding.module() {
+                    // form the path
+                    let path_segments = match module.parent_link {
+                        NoParentLink => path_segments.clone(),
+                        ModuleParentLink(_, name) => {
+                            let mut paths = path_segments.clone();
+                            let ident = hir::Ident::from_name(name);
+                            let params = PathParameters::none();
+                            let segm = PathSegment {
+                                identifier: ident,
+                                parameters: params,
+                            };
+                            paths.push(segm);
+                            paths
+                        }
+                        _ => unreachable!(),
+                    };
+
+                    if !in_module_is_extern || name_binding.is_public() {
+                        // add the module to the lookup
+                        let is_extern = in_module_is_extern || module.is_extern_crate;
+                        worklist.push((module, path_segments, is_extern));
+                    }
+                }
+            })
+        }
+
+        SuggestedCandidates {
+            name: lookup_name.as_str().to_string(),
+            candidates: lookup_results,
+        }
+    }
+
     fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) {
         debug!("(recording def) recording {:?} for {}", resolution, node_id);
         assert!(match resolution.last_private {
@@ -3513,6 +3657,67 @@ fn path_names_to_string(path: &Path, depth: usize) -> String {
     names_to_string(&names[..])
 }
 
+/// When an entity with a given name is not available in scope, we search for
+/// entities with that name in all crates. This method allows outputting the
+/// results of this search in a programmer-friendly way
+fn show_candidates(session: &mut DiagnosticBuilder,
+                   span: syntax::codemap::Span,
+                   candidates: &SuggestedCandidates) {
+
+    let paths = &candidates.candidates;
+
+    if paths.len() > 0 {
+        // don't show more than MAX_CANDIDATES results, so
+        // we're consistent with the trait suggestions
+        const MAX_CANDIDATES: usize = 5;
+
+        // we want consistent results across executions, but candidates are produced
+        // by iterating through a hash map, so make sure they are ordered:
+        let mut path_strings: Vec<_> = paths.into_iter()
+                                            .map(|p| path_names_to_string(&p, 0))
+                                            .collect();
+        path_strings.sort();
+
+        // behave differently based on how many candidates we have:
+        if !paths.is_empty() {
+            if paths.len() == 1 {
+                session.fileline_help(
+                    span,
+                    &format!("you can to import it into scope: `use {};`.",
+                        &path_strings[0]),
+                );
+            } else {
+                session.fileline_help(span, "you can import several candidates \
+                    into scope (`use ...;`):");
+                let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
+
+                for (idx, path_string) in path_strings.iter().enumerate() {
+                    if idx == MAX_CANDIDATES - 1 && count > 1 {
+                        session.fileline_help(
+                            span,
+                            &format!("  and {} other candidates", count).to_string(),
+                        );
+                        break;
+                    } else {
+                        session.fileline_help(
+                            span,
+                            &format!("  `{}`", path_string).to_string(),
+                        );
+                    }
+                }
+            }
+        }
+    } else {
+        // nothing found:
+        session.fileline_help(
+            span,
+            &format!("no candidates by the name of `{}` found in your \
+            project; maybe you misspelled the name or forgot to import \
+            an external crate?", candidates.name.to_string()),
+        );
+    };
+}
+
 /// A somewhat inefficient routine to obtain the name of a module.
 fn module_to_string(module: Module) -> String {
     let mut names = Vec::new();
diff --git a/src/test/auxiliary/issue-21221-3.rs b/src/test/auxiliary/issue-21221-3.rs
new file mode 100644
index 00000000000..fae0fe16a26
--- /dev/null
+++ b/src/test/auxiliary/issue-21221-3.rs
@@ -0,0 +1,29 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+#![crate_type="lib"]
+
+pub mod outer {
+    // should suggest this
+    pub trait OuterTrait {}
+
+    // should not suggest this since the module is private
+    mod private_module {
+        pub trait OuterTrait {}
+    }
+
+    // should not suggest since the trait is private
+    pub mod public_module {
+        trait OuterTrait {}
+    }
+}
diff --git a/src/test/auxiliary/issue-21221-4.rs b/src/test/auxiliary/issue-21221-4.rs
new file mode 100644
index 00000000000..fffe060ee24
--- /dev/null
+++ b/src/test/auxiliary/issue-21221-4.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+#![crate_type="lib"]
+
+mod foo {
+    // should not be suggested => foo is private
+    pub trait T {}
+}
+
+// should be suggested
+pub use foo::T;
diff --git a/src/test/compile-fail/associated-types-eq-1.rs b/src/test/compile-fail/associated-types-eq-1.rs
index 58dbb986325..59d87146097 100644
--- a/src/test/compile-fail/associated-types-eq-1.rs
+++ b/src/test/compile-fail/associated-types-eq-1.rs
@@ -17,7 +17,7 @@ pub trait Foo {
 }
 
 fn foo2<I: Foo>(x: I) {
-    let _: A = x.boo(); //~ERROR use of undeclared
+    let _: A = x.boo(); //~ERROR undefined or not in scope
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/bad-type-env-capture.rs b/src/test/compile-fail/bad-type-env-capture.rs
index 4e5dc652fb5..a3139905244 100644
--- a/src/test/compile-fail/bad-type-env-capture.rs
+++ b/src/test/compile-fail/bad-type-env-capture.rs
@@ -10,6 +10,6 @@
 
 fn foo<T>() {
     fn bar(b: T) { } //~ ERROR can't use type parameters from outer
-    //~^ ERROR use of undeclared type name
+    //~^ ERROR type name `T` is undefined or not in scope
 }
 fn main() { }
diff --git a/src/test/compile-fail/extern-with-type-bounds.rs b/src/test/compile-fail/extern-with-type-bounds.rs
index 2553bdcbb27..d8bdd5974c7 100644
--- a/src/test/compile-fail/extern-with-type-bounds.rs
+++ b/src/test/compile-fail/extern-with-type-bounds.rs
@@ -24,7 +24,7 @@ extern "rust-intrinsic" {
 
     // Unresolved bounds should still error.
     fn align_of<T: NoSuchTrait>() -> usize;
-    //~^ ERROR use of undeclared trait name `NoSuchTrait`
+    //~^ ERROR trait `NoSuchTrait` is not in scope
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/glob-resolve1.rs b/src/test/compile-fail/glob-resolve1.rs
index 181503db818..1e5662aa172 100644
--- a/src/test/compile-fail/glob-resolve1.rs
+++ b/src/test/compile-fail/glob-resolve1.rs
@@ -35,7 +35,7 @@ fn main() {
     C; //~ ERROR: unresolved
     import(); //~ ERROR: unresolved
 
-    foo::<A>(); //~ ERROR: undeclared
-    foo::<C>(); //~ ERROR: undeclared
-    foo::<D>(); //~ ERROR: undeclared
+    foo::<A>(); //~ ERROR: not in scope
+    foo::<C>(); //~ ERROR: not in scope
+    foo::<D>(); //~ ERROR: not in scope
 }
diff --git a/src/test/compile-fail/inner-static-type-parameter.rs b/src/test/compile-fail/inner-static-type-parameter.rs
index 56b681378cc..6fcda66486b 100644
--- a/src/test/compile-fail/inner-static-type-parameter.rs
+++ b/src/test/compile-fail/inner-static-type-parameter.rs
@@ -15,7 +15,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
 fn foo<T>() {
     static a: Bar<T> = Bar::What;
     //~^ ERROR cannot use an outer type parameter in this context
-    //~| ERROR use of undeclared type name `T`
+    //~| ERROR type name `T` is undefined or not in scope
 }
 
 fn main() {
diff --git a/src/test/compile-fail/issue-18058.rs b/src/test/compile-fail/issue-18058.rs
index bbb540200b4..0447cf781ff 100644
--- a/src/test/compile-fail/issue-18058.rs
+++ b/src/test/compile-fail/issue-18058.rs
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 impl Undefined {}
-//~^ ERROR use of undeclared type name `Undefined`
+//~^ ERROR type name `Undefined` is undefined or not in scope
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-18119.rs b/src/test/compile-fail/issue-18119.rs
index 1270b094534..f06496463e4 100644
--- a/src/test/compile-fail/issue-18119.rs
+++ b/src/test/compile-fail/issue-18119.rs
@@ -13,10 +13,10 @@ static Y: u8 = 1;
 fn foo() {}
 
 impl X {}
-//~^ ERROR use of undeclared type name `X`
+//~^ ERROR type name `X` is undefined or not in scope
 impl Y {}
-//~^ ERROR use of undeclared type name `Y`
+//~^ ERROR type name `Y` is undefined or not in scope
 impl foo {}
-//~^ ERROR use of undeclared type name `foo`
+//~^ ERROR type name `foo` is undefined or not in scope
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-19883.rs b/src/test/compile-fail/issue-19883.rs
index 7ec3093a6e0..3a7a1692f38 100644
--- a/src/test/compile-fail/issue-19883.rs
+++ b/src/test/compile-fail/issue-19883.rs
@@ -17,7 +17,7 @@ trait From<Src> {
 trait To: Sized {
     fn to<Dst: From<Self>>(self) ->
         <Dst as From<Self>>::Dst
-        //~^ ERROR use of undeclared associated type `From::Dst`
+        //~^ ERROR associated type `From::Dst` is undefined or not in scope
     {
         From::from(self)
     }
diff --git a/src/test/compile-fail/issue-21221-1.rs b/src/test/compile-fail/issue-21221-1.rs
new file mode 100644
index 00000000000..03dd7b6754a
--- /dev/null
+++ b/src/test/compile-fail/issue-21221-1.rs
@@ -0,0 +1,94 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod mul1 {
+    pub trait Mul {}
+}
+
+mod mul2 {
+    pub trait Mul {}
+}
+
+mod mul3 {
+    enum Mul {
+      Yes,
+      No
+    }
+}
+
+mod mul4 {
+    type Mul = String;
+}
+
+mod mul5 {
+    struct Mul{
+        left_term: u32,
+        right_term: u32
+    }
+}
+
+#[derive(Debug)]
+struct Foo;
+
+// When we comment the next line:
+//use mul1::Mul;
+
+// BEFORE, we got the following error for the `impl` below:
+//   error: use of undeclared trait name `Mul` [E0405]
+// AFTER, we get this message:
+//   error: trait `Mul` is not in scope.
+//   help: ...
+//   help: you can import several candidates into scope (`use ...;`):
+//   help:   `mul1::Mul`
+//   help:   `mul2::Mul`
+//   help:   `std::ops::Mul`
+
+impl Mul for Foo {
+//~^ ERROR trait `Mul` is not in scope
+//~| HELP `mul1::Mul`
+//~| HELP `mul2::Mul`
+//~| HELP `std::ops::Mul`
+}
+
+// BEFORE, we got:
+//   error: use of undeclared type name `Mul` [E0412]
+// AFTER, we get:
+//   error: type name `Mul` is not in scope. Maybe you meant:
+//   help: ...
+//   help: you can import several candidates into scope (`use ...;`):
+//   help:   `mul1::Mul`
+//   help:   `mul2::Mul`
+//   help:   `mul3::Mul`
+//   help:   `mul4::Mul`
+//   help:   and 2 other candidates
+fn getMul() -> Mul {
+//~^ ERROR type name `Mul` is undefined or not in scope
+//~| HELP `mul1::Mul`
+//~| HELP `mul2::Mul`
+//~| HELP `mul3::Mul`
+//~| HELP `mul4::Mul`
+//~| HELP and 2 other candidates
+}
+
+// Let's also test what happens if the trait doesn't exist:
+impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
+//~^ ERROR trait `ThisTraitReallyDoesntExistInAnyModuleReally` is not in scope
+}
+
+// Let's also test what happens if there's just one alternative:
+impl Div for Foo {
+//~^ ERROR trait `Div` is not in scope
+//~| HELP `use std::ops::Div;`
+}
+
+fn main() {
+    let foo = Foo();
+    println!("Hello, {:?}!", foo);
+}
diff --git a/src/test/compile-fail/issue-21221-2.rs b/src/test/compile-fail/issue-21221-2.rs
new file mode 100644
index 00000000000..4145d20dea5
--- /dev/null
+++ b/src/test/compile-fail/issue-21221-2.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod foo {
+    pub mod bar {
+        // note: trait T is not public, but being in the current
+        // crate, it's fine to show it, since the programmer can
+        // decide to make it public based on the suggestion ...
+        trait T {}
+    }
+    // imports should be ignored:
+    use self::bar::T;
+}
+
+pub mod baz {
+    pub use foo;
+    pub use std::ops::{Mul as T};
+}
+
+struct Foo;
+impl T for Foo { }
+//~^ ERROR trait `T` is not in scope
+//~| HELP you can to import it into scope: `use foo::bar::T;`.
diff --git a/src/test/compile-fail/issue-21221-3.rs b/src/test/compile-fail/issue-21221-3.rs
new file mode 100644
index 00000000000..ba66496b930
--- /dev/null
+++ b/src/test/compile-fail/issue-21221-3.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+// aux-build:issue-21221-3.rs
+
+extern crate issue_21221_3;
+
+struct Foo;
+
+// NOTE: This shows only traits accessible from the current
+// crate, thus the two private entities:
+//   `issue_21221_3::outer::private_module::OuterTrait` and
+//   `issue_21221_3::outer::public_module::OuterTrait`
+// are hidden from the view.
+impl OuterTrait for Foo {}
+//~^ ERROR trait `OuterTrait` is not in scope
+//~| HELP you can to import it into scope: `use issue_21221_3::outer::OuterTrait;`.
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/compile-fail/issue-21221-4.rs b/src/test/compile-fail/issue-21221-4.rs
new file mode 100644
index 00000000000..8d09510ae09
--- /dev/null
+++ b/src/test/compile-fail/issue-21221-4.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+// aux-build:issue-21221-4.rs
+
+extern crate issue_21221_4;
+
+struct Foo;
+
+impl T for Foo {}
+//~^ ERROR trait `T` is not in scope
+//~| HELP you can to import it into scope: `use issue_21221_4::T;`.
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/compile-fail/issue-22037.rs b/src/test/compile-fail/issue-22037.rs
index 3c8e7a2be0c..74f1be95420 100644
--- a/src/test/compile-fail/issue-22037.rs
+++ b/src/test/compile-fail/issue-22037.rs
@@ -11,7 +11,7 @@
 trait A {
     type Output;
     fn a(&self) -> <Self as A>::X;
-//~^ ERROR: use of undeclared associated type `A::X`
+//~^ ERROR: associated type `A::X` is undefined or not in scope
 }
 
 impl A for u32 {
diff --git a/src/test/compile-fail/issue-22384.rs b/src/test/compile-fail/issue-22384.rs
index 368e2483533..46a43bdfcb8 100644
--- a/src/test/compile-fail/issue-22384.rs
+++ b/src/test/compile-fail/issue-22384.rs
@@ -14,5 +14,5 @@ trait Trait {
 
 fn main() {
     <<i32 as Copy>::foobar as Trait>::foo();
-    //~^ ERROR use of undeclared associated type `Copy::foobar`
+    //~^ ERROR associated type `Copy::foobar` is undefined or not in scope
 }
diff --git a/src/test/compile-fail/issue-3021-c.rs b/src/test/compile-fail/issue-3021-c.rs
index 5b3e343deea..03473bd44cc 100644
--- a/src/test/compile-fail/issue-3021-c.rs
+++ b/src/test/compile-fail/issue-3021-c.rs
@@ -13,8 +13,8 @@ fn siphash<T>() {
     trait t {
         fn g(&self, x: T) -> T;  //~ ERROR can't use type parameters from outer function; try using
         //~^ ERROR can't use type parameters from outer function; try using
-        //~^^ ERROR use of undeclared type name `T`
-        //~^^^ ERROR use of undeclared type name `T`
+        //~^^ ERROR type name `T` is undefined or not in scope
+        //~^^^ ERROR type name `T` is undefined or not in scope
     }
 }
 
diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs
index 27b7fb75275..4f955df8205 100644
--- a/src/test/compile-fail/issue-3214.rs
+++ b/src/test/compile-fail/issue-3214.rs
@@ -11,7 +11,7 @@
 fn foo<T>() {
     struct foo {
         x: T, //~ ERROR can't use type parameters from outer function;
-        //~^ ERROR use of undeclared type name
+        //~^ ERROR type name `T` is undefined or not in scope
     }
 
     impl<T> Drop for foo<T> {
diff --git a/src/test/compile-fail/issue-4366-2.rs b/src/test/compile-fail/issue-4366-2.rs
index e8dfac45447..a6fe719509c 100644
--- a/src/test/compile-fail/issue-4366-2.rs
+++ b/src/test/compile-fail/issue-4366-2.rs
@@ -23,7 +23,7 @@ mod a {
     pub mod sub {
         use a::b::*;
         fn sub() -> bar { 1 }
-        //~^ ERROR: undeclared type name
+        //~^ ERROR: type name `bar` is undefined or not in scope
     }
 }
 
diff --git a/src/test/compile-fail/issue-5997-enum.rs b/src/test/compile-fail/issue-5997-enum.rs
index ad485f2d330..20d239c6ae0 100644
--- a/src/test/compile-fail/issue-5997-enum.rs
+++ b/src/test/compile-fail/issue-5997-enum.rs
@@ -11,7 +11,7 @@
 fn f<Z>() -> bool {
     enum E { V(Z) }
     //~^ ERROR can't use type parameters from outer function
-    //~^^ ERROR use of undeclared type name `Z`
+    //~^^ ERROR type name `Z` is undefined or not in scope
     true
 }
 
diff --git a/src/test/compile-fail/issue-5997-struct.rs b/src/test/compile-fail/issue-5997-struct.rs
index 587c7c63f4c..40be2f04cb4 100644
--- a/src/test/compile-fail/issue-5997-struct.rs
+++ b/src/test/compile-fail/issue-5997-struct.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 fn f<T>() -> bool {
-    struct S(T); //~ ERROR use of undeclared type name `T`
+    struct S(T); //~ ERROR type name `T` is undefined or not in scope
     //~^ ERROR can't use type parameters from outer function; try using
 
     true
diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs
index 40c3d96bc9a..96ac2de1762 100644
--- a/src/test/compile-fail/issue-7607-1.rs
+++ b/src/test/compile-fail/issue-7607-1.rs
@@ -12,7 +12,7 @@ struct Foo {
     x: isize
 }
 
-impl Fo { //~ ERROR use of undeclared type name `Fo`
+impl Fo { //~ ERROR type name `Fo` is undefined or not in scope
     fn foo() {}
 }
 
diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs
index 96c8ec45058..1c97c0c886d 100644
--- a/src/test/compile-fail/issue-8767.rs
+++ b/src/test/compile-fail/issue-8767.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-impl B { //~ ERROR use of undeclared type name `B`
+impl B { //~ ERROR type name `B` is undefined or not in scope
 }
 
 fn main() {
diff --git a/src/test/compile-fail/no-implicit-prelude-nested.rs b/src/test/compile-fail/no-implicit-prelude-nested.rs
index 526750257d2..af1046bcd5d 100644
--- a/src/test/compile-fail/no-implicit-prelude-nested.rs
+++ b/src/test/compile-fail/no-implicit-prelude-nested.rs
@@ -18,11 +18,11 @@
 mod foo {
     mod baz {
         struct Test;
-        impl Add for Test {} //~ ERROR: use of undeclared trait
-        impl Clone for Test {} //~ ERROR: use of undeclared trait
-        impl Iterator for Test {} //~ ERROR: use of undeclared trait
-        impl ToString for Test {} //~ ERROR: use of undeclared trait
-        impl Writer for Test {} //~ ERROR: use of undeclared trait
+        impl Add for Test {} //~ ERROR: not in scope
+        impl Clone for Test {} //~ ERROR: not in scope
+        impl Iterator for Test {} //~ ERROR: not in scope
+        impl ToString for Test {} //~ ERROR: not in scope
+        impl Writer for Test {} //~ ERROR: not in scope
 
         fn foo() {
             drop(2) //~ ERROR: unresolved name
@@ -30,11 +30,11 @@ mod foo {
     }
 
     struct Test;
-    impl Add for Test {} //~ ERROR: use of undeclared trait
-    impl Clone for Test {} //~ ERROR: use of undeclared trait
-    impl Iterator for Test {} //~ ERROR: use of undeclared trait
-    impl ToString for Test {} //~ ERROR: use of undeclared trait
-    impl Writer for Test {} //~ ERROR: use of undeclared trait
+    impl Add for Test {} //~ ERROR: not in scope
+    impl Clone for Test {} //~ ERROR: not in scope
+    impl Iterator for Test {} //~ ERROR: not in scope
+    impl ToString for Test {} //~ ERROR: not in scope
+    impl Writer for Test {} //~ ERROR: not in scope
 
     fn foo() {
         drop(2) //~ ERROR: unresolved name
@@ -45,11 +45,11 @@ fn qux() {
     #[no_implicit_prelude]
     mod qux_inner {
         struct Test;
-        impl Add for Test {} //~ ERROR: use of undeclared trait
-        impl Clone for Test {} //~ ERROR: use of undeclared trait
-        impl Iterator for Test {} //~ ERROR: use of undeclared trait
-        impl ToString for Test {} //~ ERROR: use of undeclared trait
-        impl Writer for Test {} //~ ERROR: use of undeclared trait
+        impl Add for Test {} //~ ERROR: not in scope
+        impl Clone for Test {} //~ ERROR: not in scope
+        impl Iterator for Test {} //~ ERROR: not in scope
+        impl ToString for Test {} //~ ERROR: not in scope
+        impl Writer for Test {} //~ ERROR: not in scope
 
         fn foo() {
             drop(2) //~ ERROR: unresolved name
diff --git a/src/test/compile-fail/no-implicit-prelude.rs b/src/test/compile-fail/no-implicit-prelude.rs
index c4bcd33b93b..4693fd14e7d 100644
--- a/src/test/compile-fail/no-implicit-prelude.rs
+++ b/src/test/compile-fail/no-implicit-prelude.rs
@@ -17,11 +17,11 @@
 // fail with the same error message).
 
 struct Test;
-impl Add for Test {} //~ ERROR: use of undeclared trait
-impl Clone for Test {} //~ ERROR: use of undeclared trait
-impl Iterator for Test {} //~ ERROR: use of undeclared trait
-impl ToString for Test {} //~ ERROR: use of undeclared trait
-impl Writer for Test {} //~ ERROR: use of undeclared trait
+impl Add for Test {} //~ ERROR: not in scope
+impl Clone for Test {} //~ ERROR: not in scope
+impl Iterator for Test {} //~ ERROR: not in scope
+impl ToString for Test {} //~ ERROR: not in scope
+impl Writer for Test {} //~ ERROR: not in scope
 
 fn main() {
     drop(2) //~ ERROR: unresolved name
diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs
index 5952f05b7bc..dcab3a46b0a 100644
--- a/src/test/compile-fail/privacy-ns1.rs
+++ b/src/test/compile-fail/privacy-ns1.rs
@@ -42,7 +42,7 @@ pub mod foo2 {
 fn test_glob2() {
     use foo2::*;
 
-    let _x: Box<Bar>;  //~ ERROR use of undeclared type name `Bar`
+    let _x: Box<Bar>;  //~ ERROR type name `Bar` is undefined or not in scope
 }
 
 // neither public
@@ -58,7 +58,7 @@ fn test_glob3() {
     use foo3::*;
 
     Bar();  //~ ERROR unresolved name `Bar`
-    let _x: Box<Bar>;  //~ ERROR  use of undeclared type name `Bar`
+    let _x: Box<Bar>;  //~ ERROR  type name `Bar` is undefined or not in scope
 }
 
 fn main() {
diff --git a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs
index 88f09233d10..92134ecde91 100644
--- a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs
+++ b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs
@@ -18,7 +18,7 @@ trait TraitA<A> {
             //~^ ERROR parameter `B` is never used
             Variance(A)
                 //~^ ERROR can't use type parameters from outer function
-                //~^^ ERROR use of undeclared type name `A`
+                //~^^ ERROR type name `A` is undefined or not in scope
         }
     }
 }
@@ -27,7 +27,7 @@ trait TraitB<A> {
     fn outer(self) {
         struct Foo<B>(A);
                 //~^ ERROR can't use type parameters from outer function
-                //~^^ ERROR use of undeclared type name `A`
+                //~^^ ERROR type name `A` is undefined or not in scope
                 //~^^^ ERROR parameter `B` is never used
     }
 }
@@ -36,7 +36,7 @@ trait TraitC<A> {
     fn outer(self) {
         struct Foo<B> { a: A }
                 //~^ ERROR can't use type parameters from outer function
-                //~^^ ERROR use of undeclared type name `A`
+                //~^^ ERROR type name `A` is undefined or not in scope
                 //~^^^ ERROR parameter `B` is never used
     }
 }
@@ -45,7 +45,7 @@ trait TraitD<A> {
     fn outer(self) {
         fn foo<B>(a: A) { }
                 //~^ ERROR can't use type parameters from outer function
-                //~^^ ERROR use of undeclared type name `A`
+                //~^^ ERROR type name `A` is undefined or not in scope
     }
 }
 
diff --git a/src/test/compile-fail/resolve-unknown-trait.rs b/src/test/compile-fail/resolve-unknown-trait.rs
index fd4dce51fc8..dae3a79832b 100644
--- a/src/test/compile-fail/resolve-unknown-trait.rs
+++ b/src/test/compile-fail/resolve-unknown-trait.rs
@@ -10,10 +10,10 @@
 
 
 trait NewTrait : SomeNonExistentTrait {}
-//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
+//~^ ERROR trait `SomeNonExistentTrait` is not in scope
 
 impl SomeNonExistentTrait for isize {}
-//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
+//~^ ERROR trait `SomeNonExistentTrait` is not in scope
 
 fn f<T:SomeNonExistentTrait>() {}
-//~^ ERROR use of undeclared trait name `SomeNonExistentTrait`
+//~^ ERROR trait `SomeNonExistentTrait` is not in scope
diff --git a/src/test/compile-fail/trait-impl-for-module.rs b/src/test/compile-fail/trait-impl-for-module.rs
index 969b6398fdb..c04e197b6bd 100644
--- a/src/test/compile-fail/trait-impl-for-module.rs
+++ b/src/test/compile-fail/trait-impl-for-module.rs
@@ -14,7 +14,7 @@ mod a {
 trait A {
 }
 
-impl A for a { //~ ERROR use of undeclared type name `a`
+impl A for a { //~ ERROR type name `a` is undefined or not in scope
 }
 
 fn main() {
diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
index b195a932aca..21450856ae6 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
@@ -10,7 +10,7 @@
 
 #![feature(unboxed_closures)]
 
-fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR undeclared trait name `Nonexist`
+fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR trait `Nonexist` is not in scope
 
 type Typedef = isize;