diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 87f130daa42b4..56e8c75b859a1 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2191,11 +2191,9 @@ impl<'a> Resolver<'a> {
             }
 
             // Try Levenshtein if nothing else worked.
-            if path.len() == 1 {
-                if let Some(candidate) = this.lookup_typo_candidate(name, ns, is_expected) {
-                    err.span_label(span, &format!("did you mean `{}`?", candidate));
-                    return err;
-                }
+            if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
+                err.span_label(span, &format!("did you mean `{}`?", candidate));
+                return err;
             }
 
             // Fallback label.
@@ -2649,21 +2647,72 @@ impl<'a> Resolver<'a> {
     }
 
     fn lookup_typo_candidate<FilterFn>(&mut self,
-                                       name: Name,
+                                       path: &[Ident],
                                        ns: Namespace,
                                        filter_fn: FilterFn)
-                                       -> Option<Name>
+                                       -> Option<String>
         where FilterFn: Fn(Def) -> bool
     {
-        // FIXME: bindings in ribs provide quite modest set of candidates,
-        // extend it with other names in scope.
-        let names = self.ribs[ns].iter().rev().flat_map(|rib| {
-            rib.bindings.iter().filter_map(|(ident, def)| {
-                if filter_fn(*def) { Some(&ident.name) } else { None }
-            })
-        });
-        match find_best_match_for_name(names, &name.as_str(), None) {
-            Some(found) if found != name => Some(found),
+        let add_module_candidates = |module: Module, names: &mut Vec<Name>| {
+            for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
+                if let Some(binding) = resolution.borrow().binding {
+                    if filter_fn(binding.def()) {
+                        names.push(ident.name);
+                    }
+                }
+            }
+        };
+
+        let mut names = Vec::new();
+        let prefix_str = if path.len() == 1 {
+            // Search in lexical scope.
+            // Walk backwards up the ribs in scope and collect candidates.
+            for rib in self.ribs[ns].iter().rev() {
+                // Locals and type parameters
+                for (ident, def) in &rib.bindings {
+                    if filter_fn(*def) {
+                        names.push(ident.name);
+                    }
+                }
+                // Items in scope
+                if let ModuleRibKind(module) = rib.kind {
+                    // Items from this module
+                    add_module_candidates(module, &mut names);
+
+                    if let ModuleKind::Block(..) = module.kind {
+                        // We can see through blocks
+                    } else {
+                        // Items from the prelude
+                        if let Some(prelude) = self.prelude {
+                            if !module.no_implicit_prelude {
+                                add_module_candidates(prelude, &mut names);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            // Add primitive types to the mix
+            if filter_fn(Def::PrimTy(TyBool)) {
+                for (name, _) in &self.primitive_type_table.primitive_types {
+                    names.push(*name);
+                }
+            }
+            String::new()
+        } else {
+            // Search in module.
+            let mod_path = &path[..path.len() - 1];
+            if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) {
+                add_module_candidates(module, &mut names);
+            }
+            names_to_string(mod_path) + "::"
+        };
+
+        let name = path[path.len() - 1].name;
+        // Make sure error reporting is deterministic.
+        names.sort_by_key(|name| name.as_str());
+        match find_best_match_for_name(names.iter(), &name.as_str(), None) {
+            Some(found) if found != name => Some(format!("{}{}", prefix_str, found)),
             _ => None,
         }
     }
diff --git a/src/test/ui/resolve/levenshtein.rs b/src/test/ui/resolve/levenshtein.rs
new file mode 100644
index 0000000000000..53b6372d8eb40
--- /dev/null
+++ b/src/test/ui/resolve/levenshtein.rs
@@ -0,0 +1,33 @@
+// 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.
+
+const MAX_ITEM: usize = 10;
+
+fn foo_bar() {}
+
+fn foo(c: esize) {} // Misspelled primitive type name.
+
+enum Bar { }
+
+type A = Baz; // Misspelled type name.
+type B = Opiton<u8>; // Misspelled type name from the prelude.
+
+mod m {
+    type A = Baz; // No suggestion here, Bar is not visible
+
+    pub struct First;
+    pub struct Second;
+}
+
+fn main() {
+    let v = [0u32; MAXITEM]; // Misspelled constant name.
+    foobar(); // Misspelled function name.
+    let b: m::first = m::second; // Misspelled item in module.
+}
diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr
new file mode 100644
index 0000000000000..d01ffcb2839b4
--- /dev/null
+++ b/src/test/ui/resolve/levenshtein.stderr
@@ -0,0 +1,56 @@
+error[E0412]: cannot find type `esize` in this scope
+  --> $DIR/levenshtein.rs:15:11
+   |
+15 | fn foo(c: esize) {} // Misspelled primitive type name.
+   |           ^^^^^ did you mean `isize`?
+
+error[E0412]: cannot find type `Baz` in this scope
+  --> $DIR/levenshtein.rs:19:10
+   |
+19 | type A = Baz; // Misspelled type name.
+   |          ^^^ did you mean `Bar`?
+
+error[E0412]: cannot find type `Opiton` in this scope
+  --> $DIR/levenshtein.rs:20:10
+   |
+20 | type B = Opiton<u8>; // Misspelled type name from the prelude.
+   |          ^^^^^^^^^^ did you mean `Option`?
+
+error[E0412]: cannot find type `Baz` in this scope
+  --> $DIR/levenshtein.rs:23:14
+   |
+23 |     type A = Baz; // No suggestion here, Bar is not visible
+   |              ^^^ not found in this scope
+
+error[E0425]: cannot find value `MAXITEM` in this scope
+  --> $DIR/levenshtein.rs:30:20
+   |
+30 |     let v = [0u32; MAXITEM]; // Misspelled constant name.
+   |                    ^^^^^^^ did you mean `MAX_ITEM`?
+
+error[E0425]: cannot find function `foobar` in this scope
+  --> $DIR/levenshtein.rs:31:5
+   |
+31 |     foobar(); // Misspelled function name.
+   |     ^^^^^^ did you mean `foo_bar`?
+
+error[E0412]: cannot find type `first` in module `m`
+  --> $DIR/levenshtein.rs:32:12
+   |
+32 |     let b: m::first = m::second; // Misspelled item in module.
+   |            ^^^^^^^^ did you mean `m::First`?
+
+error[E0425]: cannot find value `second` in module `m`
+  --> $DIR/levenshtein.rs:32:23
+   |
+32 |     let b: m::first = m::second; // Misspelled item in module.
+   |                       ^^^^^^^^^ did you mean `m::Second`?
+
+error[E0080]: constant evaluation error
+  --> $DIR/levenshtein.rs:30:20
+   |
+30 |     let v = [0u32; MAXITEM]; // Misspelled constant name.
+   |                    ^^^^^^^ unresolved path in constant expression
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
index 8ace738ad6d81..57c0ecc813505 100644
--- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
+++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
@@ -32,7 +32,7 @@ error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12
    |
 55 |     v.push(a::b);
-   |            ^^^^ not a value
+   |            ^^^^ did you mean `a::I`?
 
 error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5
@@ -44,13 +44,13 @@ error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5
    |
 67 |     a::b
-   |     ^^^^ not a value
+   |     ^^^^ did you mean `a::I`?
 
 error[E0423]: expected function, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5
    |
 73 |     a::b()
-   |     ^^^^ not a function
+   |     ^^^^ did you mean `a::I`?
 
 error: main function not found