about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-08-08 02:39:02 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-08-10 13:16:06 +0300
commitff85d1c2d28e19797b9d9aa67bbdfaf92e015c57 (patch)
treebefe455069eef2c4ec04ed2049d9b0145d9dcb71
parente2e8746acc1d4fd236552a59f54b732680b4524e (diff)
downloadrust-ff85d1c2d28e19797b9d9aa67bbdfaf92e015c57.tar.gz
rust-ff85d1c2d28e19797b9d9aa67bbdfaf92e015c57.zip
resolve: Move late resolution visitor into a separate file
-rw-r--r--src/librustc_resolve/diagnostics.rs688
-rw-r--r--src/librustc_resolve/late.rs1806
-rw-r--r--src/librustc_resolve/late/diagnostics.rs769
-rw-r--r--src/librustc_resolve/lib.rs2034
4 files changed, 2663 insertions, 2634 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index c1fe7188f6d..f56954e32ae 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -1,15 +1,14 @@
 use std::cmp::Reverse;
 
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder};
 use log::debug;
-use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind};
+use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc::hir::def::Namespace::{self, *};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::PrimTy;
-use rustc::session::{Session, config::nightly_options};
+use rustc::session::Session;
 use rustc::ty::{self, DefIdTree};
 use rustc::util::nodemap::FxHashSet;
-use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
+use syntax::ast::{self, Ident, Path};
 use syntax::ext::base::MacroKind;
 use syntax::feature_gate::BUILTIN_ATTRIBUTES;
 use syntax::symbol::{Symbol, kw};
@@ -17,40 +16,33 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{BytePos, Span};
 
 use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
-use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS};
-use crate::{CrateLint, LateResolutionVisitor, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment};
+use crate::{path_names_to_string, KNOWN_TOOLS};
+use crate::{CrateLint, LegacyScope, Module, ModuleOrUniformRoot};
+use crate::{PathResult, ParentScope, Resolver, Scope, ScopeSet, Segment};
 
 type Res = def::Res<ast::NodeId>;
 
 /// A vector of spans and replacements, a message and applicability.
 crate type Suggestion = (Vec<(Span, String)>, String, Applicability);
 
-/// A field or associated item from self type suggested in case of resolution failure.
-enum AssocSuggestion {
-    Field,
-    MethodWithSelf,
-    AssocItem,
-}
-
-struct TypoSuggestion {
-    candidate: Symbol,
-    res: Res,
+crate struct TypoSuggestion {
+    pub candidate: Symbol,
+    pub res: Res,
 }
 
 impl TypoSuggestion {
-    fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+    crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
         TypoSuggestion { candidate, res }
     }
 }
 
 /// A free importable items suggested in case of resolution failure.
 crate struct ImportSuggestion {
-    did: Option<DefId>,
+    pub did: Option<DefId>,
     pub path: Path,
 }
 
-fn add_typo_suggestion(
+crate fn add_typo_suggestion(
     err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
 ) -> bool {
     if let Some(suggestion) = suggestion {
@@ -65,7 +57,7 @@ fn add_typo_suggestion(
     false
 }
 
-fn add_module_candidates(
+crate fn add_module_candidates(
     module: Module<'_>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool
 ) {
     for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
@@ -78,488 +70,6 @@ fn add_module_candidates(
     }
 }
 
-impl<'a> LateResolutionVisitor<'a, '_> {
-    /// Handles error reporting for `smart_resolve_path_fragment` function.
-    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
-    pub(crate) fn smart_resolve_report_errors(
-        &mut self,
-        path: &[Segment],
-        span: Span,
-        source: PathSource<'_>,
-        res: Option<Res>,
-    ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
-        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
-        let ns = source.namespace();
-        let is_expected = &|res| source.is_expected(res);
-        let is_enum_variant = &|res| {
-            if let Res::Def(DefKind::Variant, _) = res { true } else { false }
-        };
-
-        // Make the base error.
-        let expected = source.descr_expected();
-        let path_str = Segment::names_to_string(path);
-        let item_str = path.last().unwrap().ident;
-        let code = source.error_code(res.is_some());
-        let (base_msg, fallback_label, base_span) = if let Some(res) = res {
-            (format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
-                format!("not a {}", expected),
-                span)
-        } else {
-            let item_span = path.last().unwrap().ident.span;
-            let (mod_prefix, mod_str) = if path.len() == 1 {
-                (String::new(), "this scope".to_string())
-            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
-                (String::new(), "the crate root".to_string())
-            } else {
-                let mod_path = &path[..path.len() - 1];
-                let mod_prefix = match self.resolve_path(
-                    mod_path, Some(TypeNS), false, span, CrateLint::No
-                ) {
-                    PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
-                        module.def_kind(),
-                    _ => None,
-                }.map_or(String::new(), |kind| format!("{} ", kind.descr()));
-                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
-            };
-            (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
-                format!("not found in {}", mod_str),
-                item_span)
-        };
-
-        let code = DiagnosticId::Error(code.into());
-        let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code);
-
-        // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
-        if ["this", "my"].contains(&&*item_str.as_str())
-            && self.self_value_is_available(path[0].ident.span, span) {
-            err.span_suggestion(
-                span,
-                "did you mean",
-                "self".to_string(),
-                Applicability::MaybeIncorrect,
-            );
-        }
-
-        // Emit special messages for unresolved `Self` and `self`.
-        if is_self_type(path, ns) {
-            __diagnostic_used!(E0411);
-            err.code(DiagnosticId::Error("E0411".into()));
-            err.span_label(span, format!("`Self` is only available in impls, traits, \
-                                          and type definitions"));
-            return (err, Vec::new());
-        }
-        if is_self_value(path, ns) {
-            debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
-
-            __diagnostic_used!(E0424);
-            err.code(DiagnosticId::Error("E0424".into()));
-            err.span_label(span, match source {
-                PathSource::Pat => {
-                    format!("`self` value is a keyword \
-                             and may not be bound to \
-                             variables or shadowed")
-                }
-                _ => {
-                    format!("`self` value is a keyword \
-                             only available in methods \
-                             with `self` parameter")
-                }
-            });
-            return (err, Vec::new());
-        }
-
-        // Try to lookup name in more relaxed fashion for better error reporting.
-        let ident = path.last().unwrap().ident;
-        let candidates = self.lookup_import_candidates(ident, ns, is_expected)
-            .drain(..)
-            .filter(|ImportSuggestion { did, .. }| {
-                match (did, res.and_then(|res| res.opt_def_id())) {
-                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
-                    _ => true,
-                }
-            })
-            .collect::<Vec<_>>();
-        let crate_def_id = DefId::local(CRATE_DEF_INDEX);
-        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
-            let enum_candidates =
-                self.lookup_import_candidates(ident, ns, is_enum_variant);
-            let mut enum_candidates = enum_candidates.iter()
-                .map(|suggestion| {
-                    import_candidate_to_enum_paths(&suggestion)
-                }).collect::<Vec<_>>();
-            enum_candidates.sort();
-
-            if !enum_candidates.is_empty() {
-                // Contextualize for E0412 "cannot find type", but don't belabor the point
-                // (that it's a variant) for E0573 "expected type, found variant".
-                let preamble = if res.is_none() {
-                    let others = match enum_candidates.len() {
-                        1 => String::new(),
-                        2 => " and 1 other".to_owned(),
-                        n => format!(" and {} others", n)
-                    };
-                    format!("there is an enum variant `{}`{}; ",
-                            enum_candidates[0].0, others)
-                } else {
-                    String::new()
-                };
-                let msg = format!("{}try using the variant's enum", preamble);
-
-                err.span_suggestions(
-                    span,
-                    &msg,
-                    enum_candidates.into_iter()
-                        .map(|(_variant_path, enum_ty_path)| enum_ty_path)
-                        // Variants re-exported in prelude doesn't mean `prelude::v1` is the
-                        // type name!
-                        // FIXME: is there a more principled way to do this that
-                        // would work for other re-exports?
-                        .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
-                        // Also write `Option` rather than `std::prelude::v1::Option`.
-                        .map(|enum_ty_path| {
-                            // FIXME #56861: DRY-er prelude filtering.
-                            enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
-                        }),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-        if path.len() == 1 && self.self_type_is_available(span) {
-            if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
-                let self_is_available = self.self_value_is_available(path[0].ident.span, span);
-                match candidate {
-                    AssocSuggestion::Field => {
-                        if self_is_available {
-                            err.span_suggestion(
-                                span,
-                                "you might have meant to use the available field",
-                                format!("self.{}", path_str),
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            err.span_label(
-                                span,
-                                "a field by this name exists in `Self`",
-                            );
-                        }
-                    }
-                    AssocSuggestion::MethodWithSelf if self_is_available => {
-                        err.span_suggestion(
-                            span,
-                            "try",
-                            format!("self.{}", path_str),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                    AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
-                        err.span_suggestion(
-                            span,
-                            "try",
-                            format!("Self::{}", path_str),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
-                return (err, candidates);
-            }
-        }
-
-        // Try Levenshtein algorithm.
-        let levenshtein_worked = add_typo_suggestion(
-            &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span
-        );
-
-        // Try context-dependent help if relaxed lookup didn't work.
-        if let Some(res) = res {
-            if self.smart_resolve_context_dependent_help(&mut err,
-                                                         span,
-                                                         source,
-                                                         res,
-                                                         &path_str,
-                                                         &fallback_label) {
-                return (err, candidates);
-            }
-        }
-
-        // Fallback label.
-        if !levenshtein_worked {
-            err.span_label(base_span, fallback_label);
-            self.type_ascription_suggestion(&mut err, base_span);
-        }
-        (err, candidates)
-    }
-}
-
-impl<'a> Resolver<'a> {
-    fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) {
-        // HACK(estebank): find a better way to figure out that this was a
-        // parser issue where a struct literal is being used on an expression
-        // where a brace being opened means a block is being started. Look
-        // ahead for the next text to see if `span` is followed by a `{`.
-        let sm = self.session.source_map();
-        let mut sp = span;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet.chars().any(|c| { !c.is_whitespace() }) {
-                        break;
-                    }
-                }
-                _ => break,
-            }
-        }
-        let followed_by_brace = match sm.span_to_snippet(sp) {
-            Ok(ref snippet) if snippet == "{" => true,
-            _ => false,
-        };
-        // In case this could be a struct literal that needs to be surrounded
-        // by parenthesis, find the appropriate span.
-        let mut i = 0;
-        let mut closing_brace = None;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet == "}" {
-                        let sp = span.to(sp);
-                        if let Ok(snippet) = sm.span_to_snippet(sp) {
-                            closing_brace = Some((sp, snippet));
-                        }
-                        break;
-                    }
-                }
-                _ => break,
-            }
-            i += 1;
-            // The bigger the span, the more likely we're incorrect --
-            // bound it to 100 chars long.
-            if i > 100 {
-                break;
-            }
-        }
-        return (followed_by_brace, closing_brace)
-    }
-}
-
-impl<'a> LateResolutionVisitor<'a, '_> {
-    /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
-    /// function.
-    /// Returns `true` if able to provide context-dependent help.
-    fn smart_resolve_context_dependent_help(
-        &mut self,
-        err: &mut DiagnosticBuilder<'a>,
-        span: Span,
-        source: PathSource<'_>,
-        res: Res,
-        path_str: &str,
-        fallback_label: &str,
-    ) -> bool {
-        let ns = source.namespace();
-        let is_expected = &|res| source.is_expected(res);
-
-        let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node {
-            ExprKind::Field(_, ident) => {
-                err.span_suggestion(
-                    expr.span,
-                    "use the path separator to refer to an item",
-                    format!("{}::{}", path_str, ident),
-                    Applicability::MaybeIncorrect,
-                );
-                true
-            }
-            ExprKind::MethodCall(ref segment, ..) => {
-                let span = expr.span.with_hi(segment.ident.span.hi());
-                err.span_suggestion(
-                    span,
-                    "use the path separator to refer to an item",
-                    format!("{}::{}", path_str, segment.ident),
-                    Applicability::MaybeIncorrect,
-                );
-                true
-            }
-            _ => false,
-        };
-
-        let mut bad_struct_syntax_suggestion = || {
-            let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
-            let mut suggested = false;
-            match source {
-                PathSource::Expr(Some(parent)) => {
-                    suggested = path_sep(err, &parent);
-                }
-                PathSource::Expr(None) if followed_by_brace == true => {
-                    if let Some((sp, snippet)) = closing_brace {
-                        err.span_suggestion(
-                            sp,
-                            "surround the struct literal with parenthesis",
-                            format!("({})", snippet),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        err.span_label(
-                            span,  // Note the parenthesis surrounding the suggestion below
-                            format!("did you mean `({} {{ /* fields */ }})`?", path_str),
-                        );
-                    }
-                    suggested = true;
-                },
-                _ => {}
-            }
-            if !suggested {
-                err.span_label(
-                    span,
-                    format!("did you mean `{} {{ /* fields */ }}`?", path_str),
-                );
-            }
-        };
-
-        match (res, source) {
-            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
-                err.span_suggestion(
-                    span,
-                    "use `!` to invoke the macro",
-                    format!("{}!", path_str),
-                    Applicability::MaybeIncorrect,
-                );
-                if path_str == "try" && span.rust_2015() {
-                    err.note("if you want the `try` keyword, you need to be in the 2018 edition");
-                }
-            }
-            (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => {
-                err.span_label(span, "type aliases cannot be used as traits");
-                if nightly_options::is_nightly_build() {
-                    err.note("did you mean to use a trait alias?");
-                }
-            }
-            (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
-                if !path_sep(err, &parent) {
-                    return false;
-                }
-            }
-            (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct)
-                | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..))  => {
-                if let Some(variants) = self.collect_enum_variants(def_id) {
-                    if !variants.is_empty() {
-                        let msg = if variants.len() == 1 {
-                            "try using the enum's variant"
-                        } else {
-                            "try using one of the enum's variants"
-                        };
-
-                        err.span_suggestions(
-                            span,
-                            msg,
-                            variants.iter().map(path_names_to_string),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                } else {
-                    err.note("did you mean to use one of the enum's variants?");
-                }
-            },
-            (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
-                if let Some((ctor_def, ctor_vis))
-                        = self.struct_constructors.get(&def_id).cloned() {
-                    let accessible_ctor = self.is_accessible_from(ctor_vis, self.current_module);
-                    if is_expected(ctor_def) && !accessible_ctor {
-                        err.span_label(
-                            span,
-                            format!("constructor is not visible here due to private fields"),
-                        );
-                    }
-                } else {
-                    bad_struct_syntax_suggestion();
-                }
-            }
-            (Res::Def(DefKind::Union, _), _) |
-            (Res::Def(DefKind::Variant, _), _) |
-            (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => {
-                bad_struct_syntax_suggestion();
-            }
-            (Res::SelfTy(..), _) if ns == ValueNS => {
-                err.span_label(span, fallback_label);
-                err.note("can't use `Self` as a constructor, you must use the implemented struct");
-            }
-            (Res::Def(DefKind::TyAlias, _), _)
-            | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => {
-                err.note("can't use a type alias as a constructor");
-            }
-            _ => return false,
-        }
-        true
-    }
-
-    fn lookup_assoc_candidate<FilterFn>(&mut self,
-                                        ident: Ident,
-                                        ns: Namespace,
-                                        filter_fn: FilterFn)
-                                        -> Option<AssocSuggestion>
-        where FilterFn: Fn(Res) -> bool
-    {
-        fn extract_node_id(t: &Ty) -> Option<NodeId> {
-            match t.node {
-                TyKind::Path(None, _) => Some(t.id),
-                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
-                // This doesn't handle the remaining `Ty` variants as they are not
-                // that commonly the self_type, it might be interesting to provide
-                // support for those in future.
-                _ => None,
-            }
-        }
-
-        // Fields are generally expected in the same contexts as locals.
-        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
-            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
-                // Look for a field with the same name in the current self_type.
-                if let Some(resolution) = self.partial_res_map.get(&node_id) {
-                    match resolution.base_res() {
-                        Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did)
-                                if resolution.unresolved_segments() == 0 => {
-                            if let Some(field_names) = self.field_names.get(&did) {
-                                if field_names.iter().any(|&field_name| ident.name == field_name) {
-                                    return Some(AssocSuggestion::Field);
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
-        }
-
-        for assoc_type_ident in &self.current_trait_assoc_types {
-            if *assoc_type_ident == ident {
-                return Some(AssocSuggestion::AssocItem);
-            }
-        }
-
-        // Look for associated items in the current trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            let parent_scope = &self.parent_scope();
-            if let Ok(binding) = self.resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    parent_scope,
-                    false,
-                    module.span,
-                ) {
-                let res = binding.res();
-                if filter_fn(res) {
-                    return Some(if self.has_self.contains(&res.def_id()) {
-                        AssocSuggestion::MethodWithSelf
-                    } else {
-                        AssocSuggestion::AssocItem
-                    });
-                }
-            }
-        }
-
-        None
-    }
-}
-
 impl<'a> Resolver<'a> {
     /// Lookup typo candidate in scope for a macro or import.
     fn early_lookup_typo_candidate(
@@ -690,103 +200,7 @@ impl<'a> Resolver<'a> {
             _ => None,
         }
     }
-}
-
-impl<'a> LateResolutionVisitor<'a, '_> {
-    fn lookup_typo_candidate(
-        &mut self,
-        path: &[Segment],
-        ns: Namespace,
-        filter_fn: &impl Fn(Res) -> bool,
-        span: Span,
-    ) -> Option<TypoSuggestion> {
-        let mut names = Vec::new();
-        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, &res) in &rib.bindings {
-                    if filter_fn(res) {
-                        names.push(TypoSuggestion::from_res(ident.name, res));
-                    }
-                }
-                // Items in scope
-                if let RibKind::ModuleRibKind(module) = rib.kind {
-                    // Items from this module
-                    add_module_candidates(module, &mut names, &filter_fn);
-
-                    if let ModuleKind::Block(..) = module.kind {
-                        // We can see through blocks
-                    } else {
-                        // Items from the prelude
-                        if !module.no_implicit_prelude {
-                            names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| {
-                                self.crate_loader
-                                    .maybe_process_path_extern(ident.name, ident.span)
-                                    .and_then(|crate_id| {
-                                        let crate_mod = Res::Def(
-                                            DefKind::Mod,
-                                            DefId {
-                                                krate: crate_id,
-                                                index: CRATE_DEF_INDEX,
-                                            },
-                                        );
-
-                                        if filter_fn(crate_mod) {
-                                            Some(TypoSuggestion::from_res(ident.name, crate_mod))
-                                        } else {
-                                            None
-                                        }
-                                    })
-                            }));
-
-                            if let Some(prelude) = self.prelude {
-                                add_module_candidates(prelude, &mut names, &filter_fn);
-                            }
-                        }
-                        break;
-                    }
-                }
-            }
-            // Add primitive types to the mix
-            if filter_fn(Res::PrimTy(PrimTy::Bool)) {
-                names.extend(
-                    self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
-                        TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
-                    })
-                )
-            }
-        } else {
-            // Search in module.
-            let mod_path = &path[..path.len() - 1];
-            if let PathResult::Module(module) = self.resolve_path(
-                mod_path, Some(TypeNS), false, span, CrateLint::No
-            ) {
-                if let ModuleOrUniformRoot::Module(module) = module {
-                    add_module_candidates(module, &mut names, &filter_fn);
-                }
-            }
-        }
-
-        let name = path[path.len() - 1].ident.name;
-        // Make sure error reporting is deterministic.
-        names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
-
-        match find_best_match_for_name(
-            names.iter().map(|suggestion| &suggestion.candidate),
-            &name.as_str(),
-            None,
-        ) {
-            Some(found) if found != name => names
-                .into_iter()
-                .find(|suggestion| suggestion.candidate == found),
-            _ => None,
-        }
-    }
-}
 
-impl<'a> Resolver<'a> {
     fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                                           lookup_ident: Ident,
                                           namespace: Namespace,
@@ -913,65 +327,6 @@ impl<'a> Resolver<'a> {
         suggestions
     }
 
-    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
-        let mut result = None;
-        let mut seen_modules = FxHashSet::default();
-        let mut worklist = vec![(self.graph_root, Vec::new())];
-
-        while let Some((in_module, path_segments)) = worklist.pop() {
-            // abort if the module is already found
-            if result.is_some() { break; }
-
-            self.populate_module_if_necessary(in_module);
-
-            in_module.for_each_child_stable(|ident, _, name_binding| {
-                // abort if the module is already found or if name_binding is private external
-                if result.is_some() || !name_binding.vis.is_visible_locally() {
-                    return
-                }
-                if let Some(module) = name_binding.module() {
-                    // form the path
-                    let mut path_segments = path_segments.clone();
-                    path_segments.push(ast::PathSegment::from_ident(ident));
-                    let module_def_id = module.def_id().unwrap();
-                    if module_def_id == def_id {
-                        let path = Path {
-                            span: name_binding.span,
-                            segments: path_segments,
-                        };
-                        result = Some((module, ImportSuggestion { did: Some(def_id), path }));
-                    } else {
-                        // add the module to the lookup
-                        if seen_modules.insert(module_def_id) {
-                            worklist.push((module, path_segments));
-                        }
-                    }
-                }
-            });
-        }
-
-        result
-    }
-
-    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
-        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
-            self.populate_module_if_necessary(enum_module);
-
-            let mut variants = Vec::new();
-            enum_module.for_each_child_stable(|ident, _, name_binding| {
-                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
-                    let mut segms = enum_import_suggestion.path.segments.clone();
-                    segms.push(ast::PathSegment::from_ident(ident));
-                    variants.push(Path {
-                        span: name_binding.span,
-                        segments: segms,
-                    });
-                }
-            });
-            variants
-        })
-    }
-
     crate fn unresolved_macro_suggestions(
         &mut self,
         err: &mut DiagnosticBuilder<'a>,
@@ -1427,21 +782,6 @@ fn find_span_immediately_after_crate_name(
     (next_left_bracket == after_second_colon, from_second_colon)
 }
 
-/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
-fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
-    let variant_path = &suggestion.path;
-    let variant_path_string = path_names_to_string(variant_path);
-
-    let path_len = suggestion.path.segments.len();
-    let enum_path = ast::Path {
-        span: suggestion.path.span,
-        segments: suggestion.path.segments[0..path_len - 1].to_vec(),
-    };
-    let enum_path_string = path_names_to_string(&enum_path);
-
-    (variant_path_string, enum_path_string)
-}
-
 /// 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
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
new file mode 100644
index 00000000000..e688857d038
--- /dev/null
+++ b/src/librustc_resolve/late.rs
@@ -0,0 +1,1806 @@
+use GenericParameters::*;
+
+use crate::{path_names_to_string, resolve_error};
+use crate::{AliasPossibility, BindingError, CrateLint, LexicalScopeBinding, Module};
+use crate::{ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
+use crate::{PathSource, ResolutionError, Resolver, Rib, RibKind, Segment, UseError};
+use crate::RibKind::*;
+
+use log::debug;
+use rustc::{bug, lint, span_bug};
+use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS};
+use rustc::hir::def::Namespace::{self, *};
+use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc::hir::TraitCandidate;
+use rustc::util::nodemap::FxHashMap;
+use smallvec::{smallvec, SmallVec};
+use syntax::{unwrap_or, walk_list};
+use syntax::ast::*;
+use syntax::ptr::P;
+use syntax::symbol::{kw, sym};
+use syntax::util::lev_distance::find_best_match_for_name;
+use syntax::visit::{self, Visitor, FnKind};
+use syntax_pos::Span;
+
+use std::collections::BTreeSet;
+use std::mem::replace;
+use std::ops::{Deref, DerefMut};
+
+mod diagnostics;
+
+type Res = def::Res<NodeId>;
+
+/// Map from the name in a pattern to its binding mode.
+type BindingMap = FxHashMap<Ident, BindingInfo>;
+
+#[derive(Copy, Clone, Debug)]
+struct BindingInfo {
+    span: Span,
+    binding_mode: BindingMode,
+}
+
+#[derive(Copy, Clone)]
+enum GenericParameters<'a, 'b> {
+    NoGenericParams,
+    HasGenericParams(// Type parameters.
+                      &'b Generics,
+
+                      // The kind of the rib used for type parameters.
+                      RibKind<'a>),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum PatternSource {
+    Match,
+    Let,
+    For,
+    FnParam,
+}
+
+impl PatternSource {
+    fn descr(self) -> &'static str {
+        match self {
+            PatternSource::Match => "match binding",
+            PatternSource::Let => "let binding",
+            PatternSource::For => "for binding",
+            PatternSource::FnParam => "function parameter",
+        }
+    }
+}
+
+struct LateResolutionVisitor<'a, 'b> {
+    resolver: &'b mut Resolver<'a>,
+
+    /// The module that represents the current item scope.
+    current_module: Module<'a>,
+
+    /// The current set of local scopes for types and values.
+    /// FIXME #4948: Reuse ribs to avoid allocation.
+    ribs: PerNS<Vec<Rib<'a>>>,
+
+    /// The current set of local scopes, for labels.
+    label_ribs: Vec<Rib<'a, NodeId>>,
+
+    /// The trait that the current context can refer to.
+    current_trait_ref: Option<(Module<'a>, TraitRef)>,
+
+    /// The current trait's associated types' ident, used for diagnostic suggestions.
+    current_trait_assoc_types: Vec<Ident>,
+
+    /// The current self type if inside an impl (used for better errors).
+    current_self_type: Option<Ty>,
+
+    /// The current self item if inside an ADT (used for better errors).
+    current_self_item: Option<NodeId>,
+
+    /// A list of labels as of yet unused. Labels will be removed from this map when
+    /// they are used (in a `break` or `continue` statement)
+    unused_labels: FxHashMap<NodeId, Span>,
+
+    /// Only used for better errors on `fn(): fn()`.
+    current_type_ascription: Vec<Span>,
+}
+
+impl<'a> Deref for LateResolutionVisitor<'a, '_> {
+    type Target = Resolver<'a>;
+    fn deref(&self) -> &Self::Target {
+        self.resolver
+    }
+}
+
+impl<'a> DerefMut for LateResolutionVisitor<'a, '_> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.resolver
+    }
+}
+
+/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
+impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
+    fn visit_item(&mut self, item: &'tcx Item) {
+        self.resolve_item(item);
+    }
+    fn visit_arm(&mut self, arm: &'tcx Arm) {
+        self.resolve_arm(arm);
+    }
+    fn visit_block(&mut self, block: &'tcx Block) {
+        self.resolve_block(block);
+    }
+    fn visit_anon_const(&mut self, constant: &'tcx AnonConst) {
+        debug!("visit_anon_const {:?}", constant);
+        self.with_constant_rib(|this| {
+            visit::walk_anon_const(this, constant);
+        });
+    }
+    fn visit_expr(&mut self, expr: &'tcx Expr) {
+        self.resolve_expr(expr, None);
+    }
+    fn visit_local(&mut self, local: &'tcx Local) {
+        self.resolve_local(local);
+    }
+    fn visit_ty(&mut self, ty: &'tcx Ty) {
+        match ty.node {
+            TyKind::Path(ref qself, ref path) => {
+                self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+            }
+            TyKind::ImplicitSelf => {
+                let self_ty = Ident::with_empty_ctxt(kw::SelfUpper);
+                let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
+                              .map_or(Res::Err, |d| d.res());
+                self.record_partial_res(ty.id, PartialRes::new(res));
+            }
+            _ => (),
+        }
+        visit::walk_ty(self, ty);
+    }
+    fn visit_poly_trait_ref(&mut self,
+                            tref: &'tcx PolyTraitRef,
+                            m: &'tcx TraitBoundModifier) {
+        self.smart_resolve_path(tref.trait_ref.ref_id, None,
+                                &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
+        visit::walk_poly_trait_ref(self, tref, m);
+    }
+    fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
+        let generic_params = match foreign_item.node {
+            ForeignItemKind::Fn(_, ref generics) => {
+                HasGenericParams(generics, ItemRibKind)
+            }
+            ForeignItemKind::Static(..) => NoGenericParams,
+            ForeignItemKind::Ty => NoGenericParams,
+            ForeignItemKind::Macro(..) => NoGenericParams,
+        };
+        self.with_generic_param_rib(generic_params, |this| {
+            visit::walk_foreign_item(this, foreign_item);
+        });
+    }
+    fn visit_fn(&mut self,
+                function_kind: FnKind<'tcx>,
+                declaration: &'tcx FnDecl,
+                _: Span,
+                _: NodeId)
+    {
+        debug!("(resolving function) entering function");
+        let rib_kind = match function_kind {
+            FnKind::ItemFn(..) => FnItemRibKind,
+            FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
+        };
+
+        // Create a value rib for the function.
+        self.ribs[ValueNS].push(Rib::new(rib_kind));
+
+        // Create a label rib for the function.
+        self.label_ribs.push(Rib::new(rib_kind));
+
+        // Add each argument to the rib.
+        let mut bindings_list = FxHashMap::default();
+        for argument in &declaration.inputs {
+            self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
+
+            self.visit_ty(&argument.ty);
+
+            debug!("(resolving function) recorded argument");
+        }
+        visit::walk_fn_ret_ty(self, &declaration.output);
+
+        // Resolve the function body, potentially inside the body of an async closure
+        match function_kind {
+            FnKind::ItemFn(.., body) |
+            FnKind::Method(.., body) => {
+                self.visit_block(body);
+            }
+            FnKind::Closure(body) => {
+                self.visit_expr(body);
+            }
+        };
+
+        debug!("(resolving function) leaving function");
+
+        self.label_ribs.pop();
+        self.ribs[ValueNS].pop();
+    }
+
+    fn visit_generics(&mut self, generics: &'tcx Generics) {
+        // For type parameter defaults, we have to ban access
+        // to following type parameters, as the InternalSubsts can only
+        // provide previous type parameters as they're built. We
+        // put all the parameters on the ban list and then remove
+        // them one by one as they are processed and become available.
+        let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
+        let mut found_default = false;
+        default_ban_rib.bindings.extend(generics.params.iter()
+            .filter_map(|param| match param.kind {
+                GenericParamKind::Const { .. } |
+                GenericParamKind::Lifetime { .. } => None,
+                GenericParamKind::Type { ref default, .. } => {
+                    found_default |= default.is_some();
+                    if found_default {
+                        Some((Ident::with_empty_ctxt(param.ident.name), Res::Err))
+                    } else {
+                        None
+                    }
+                }
+            }));
+
+        // We also ban access to type parameters for use as the types of const parameters.
+        let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
+        const_ty_param_ban_rib.bindings.extend(generics.params.iter()
+            .filter(|param| {
+                if let GenericParamKind::Type { .. } = param.kind {
+                    true
+                } else {
+                    false
+                }
+            })
+            .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err)));
+
+        for param in &generics.params {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
+                GenericParamKind::Type { ref default, .. } => {
+                    for bound in &param.bounds {
+                        self.visit_param_bound(bound);
+                    }
+
+                    if let Some(ref ty) = default {
+                        self.ribs[TypeNS].push(default_ban_rib);
+                        self.visit_ty(ty);
+                        default_ban_rib = self.ribs[TypeNS].pop().unwrap();
+                    }
+
+                    // Allow all following defaults to refer to this type parameter.
+                    default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
+                }
+                GenericParamKind::Const { ref ty } => {
+                    self.ribs[TypeNS].push(const_ty_param_ban_rib);
+
+                    for bound in &param.bounds {
+                        self.visit_param_bound(bound);
+                    }
+
+                    self.visit_ty(ty);
+
+                    const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
+                }
+            }
+        }
+        for p in &generics.where_clause.predicates {
+            self.visit_where_predicate(p);
+        }
+    }
+}
+
+impl<'a, 'b> LateResolutionVisitor<'a, '_> {
+    fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
+        let graph_root = resolver.graph_root;
+        LateResolutionVisitor {
+            resolver,
+            current_module: graph_root,
+            ribs: PerNS {
+                value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
+                type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
+                macro_ns: vec![Rib::new(ModuleRibKind(graph_root))],
+            },
+            label_ribs: Vec::new(),
+            current_trait_ref: None,
+            current_trait_assoc_types: Vec::new(),
+            current_self_type: None,
+            current_self_item: None,
+            unused_labels: Default::default(),
+            current_type_ascription: Vec::new(),
+        }
+    }
+
+    fn parent_scope(&self) -> ParentScope<'a> {
+        ParentScope { module: self.current_module, ..self.dummy_parent_scope() }
+    }
+
+    fn resolve_ident_in_lexical_scope(&mut self,
+                                      ident: Ident,
+                                      ns: Namespace,
+                                      record_used_id: Option<NodeId>,
+                                      path_span: Span)
+                                      -> Option<LexicalScopeBinding<'a>> {
+        self.resolver.resolve_ident_in_lexical_scope(
+            ident, ns, &self.parent_scope(), record_used_id, path_span, &self.ribs[ns]
+        )
+    }
+
+    fn resolve_path(
+        &mut self,
+        path: &[Segment],
+        opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        record_used: bool,
+        path_span: Span,
+        crate_lint: CrateLint,
+    ) -> PathResult<'a> {
+        self.resolver.resolve_path_with_ribs(
+            path, opt_ns, &self.parent_scope(), record_used, path_span, crate_lint, &self.ribs
+        )
+    }
+
+    // AST resolution
+    //
+    // We maintain a list of value ribs and type ribs.
+    //
+    // Simultaneously, we keep track of the current position in the module
+    // graph in the `current_module` pointer. When we go to resolve a name in
+    // the value or type namespaces, we first look through all the ribs and
+    // then query the module graph. When we resolve a name in the module
+    // namespace, we can skip all the ribs (since nested modules are not
+    // allowed within blocks in Rust) and jump straight to the current module
+    // graph node.
+    //
+    // Named implementations are handled separately. When we find a method
+    // call, we consult the module node to find all of the implementations in
+    // scope. This information is lazily cached in the module node. We then
+    // generate a fake "implementation scope" containing all the
+    // implementations thus found, for compatibility with old resolve pass.
+
+    fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
+    {
+        let id = self.definitions.local_def_id(id);
+        let module = self.module_map.get(&id).cloned(); // clones a reference
+        if let Some(module) = module {
+            // Move down in the graph.
+            let orig_module = replace(&mut self.current_module, module);
+            self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
+            self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
+
+            self.finalize_current_module_macro_resolutions(module);
+            let ret = f(self);
+
+            self.current_module = orig_module;
+            self.ribs[ValueNS].pop();
+            self.ribs[TypeNS].pop();
+            ret
+        } else {
+            f(self)
+        }
+    }
+
+    /// Searches the current set of local scopes for labels. Returns the first non-`None` label that
+    /// is returned by the given predicate function
+    ///
+    /// Stops after meeting a closure.
+    fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
+        where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R>
+    {
+        for rib in self.label_ribs.iter().rev() {
+            match rib.kind {
+                NormalRibKind => {}
+                // If an invocation of this macro created `ident`, give up on `ident`
+                // and switch to `ident`'s source from the macro definition.
+                MacroDefinition(def) => {
+                    if def == self.macro_def(ident.span.ctxt()) {
+                        ident.span.remove_mark();
+                    }
+                }
+                _ => {
+                    // Do not resolve labels across function boundary
+                    return None;
+                }
+            }
+            let r = pred(rib, ident);
+            if r.is_some() {
+                return r;
+            }
+        }
+        None
+    }
+
+    fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
+        debug!("resolve_adt");
+        self.with_current_self_item(item, |this| {
+            this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                let item_def_id = this.definitions.local_def_id(item.id);
+                this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
+                    visit::walk_item(this, item);
+                });
+            });
+        });
+    }
+
+    fn future_proof_import(&mut self, use_tree: &UseTree) {
+        let segments = &use_tree.prefix.segments;
+        if !segments.is_empty() {
+            let ident = segments[0].ident;
+            if ident.is_path_segment_keyword() || ident.span.rust_2015() {
+                return;
+            }
+
+            let nss = match use_tree.kind {
+                UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
+                _ => &[TypeNS],
+            };
+            let report_error = |this: &Self, ns| {
+                let what = if ns == TypeNS { "type parameters" } else { "local variables" };
+                this.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
+            };
+
+            for &ns in nss {
+                match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
+                    Some(LexicalScopeBinding::Res(..)) => {
+                        report_error(self, ns);
+                    }
+                    Some(LexicalScopeBinding::Item(binding)) => {
+                        let orig_blacklisted_binding =
+                            replace(&mut self.blacklisted_binding, Some(binding));
+                        if let Some(LexicalScopeBinding::Res(..)) =
+                                self.resolve_ident_in_lexical_scope(ident, ns, None,
+                                                                    use_tree.prefix.span) {
+                            report_error(self, ns);
+                        }
+                        self.blacklisted_binding = orig_blacklisted_binding;
+                    }
+                    None => {}
+                }
+            }
+        } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
+            for (use_tree, _) in use_trees {
+                self.future_proof_import(use_tree);
+            }
+        }
+    }
+
+    fn resolve_item(&mut self, item: &Item) {
+        let name = item.ident.name;
+        debug!("(resolving item) resolving {} ({:?})", name, item.node);
+
+        match item.node {
+            ItemKind::TyAlias(_, ref generics) |
+            ItemKind::OpaqueTy(_, ref generics) |
+            ItemKind::Fn(_, _, ref generics, _) => {
+                self.with_generic_param_rib(
+                    HasGenericParams(generics, ItemRibKind),
+                    |this| visit::walk_item(this, item)
+                );
+            }
+
+            ItemKind::Enum(_, ref generics) |
+            ItemKind::Struct(_, ref generics) |
+            ItemKind::Union(_, ref generics) => {
+                self.resolve_adt(item, generics);
+            }
+
+            ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
+                self.resolve_implementation(generics,
+                                            opt_trait_ref,
+                                            &self_type,
+                                            item.id,
+                                            impl_items),
+
+            ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
+                // Create a new rib for the trait-wide type parameters.
+                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                    let local_def_id = this.definitions.local_def_id(item.id);
+                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+                        this.visit_generics(generics);
+                        walk_list!(this, visit_param_bound, bounds);
+
+                        for trait_item in trait_items {
+                            this.with_trait_items(trait_items, |this| {
+                                let generic_params = HasGenericParams(
+                                    &trait_item.generics,
+                                    AssocItemRibKind,
+                                );
+                                this.with_generic_param_rib(generic_params, |this| {
+                                    match trait_item.node {
+                                        TraitItemKind::Const(ref ty, ref default) => {
+                                            this.visit_ty(ty);
+
+                                            // Only impose the restrictions of
+                                            // ConstRibKind for an actual constant
+                                            // expression in a provided default.
+                                            if let Some(ref expr) = *default{
+                                                this.with_constant_rib(|this| {
+                                                    this.visit_expr(expr);
+                                                });
+                                            }
+                                        }
+                                        TraitItemKind::Method(_, _) => {
+                                            visit::walk_trait_item(this, trait_item)
+                                        }
+                                        TraitItemKind::Type(..) => {
+                                            visit::walk_trait_item(this, trait_item)
+                                        }
+                                        TraitItemKind::Macro(_) => {
+                                            panic!("unexpanded macro in resolve!")
+                                        }
+                                    };
+                                });
+                            });
+                        }
+                    });
+                });
+            }
+
+            ItemKind::TraitAlias(ref generics, ref bounds) => {
+                // Create a new rib for the trait-wide type parameters.
+                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                    let local_def_id = this.definitions.local_def_id(item.id);
+                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+                        this.visit_generics(generics);
+                        walk_list!(this, visit_param_bound, bounds);
+                    });
+                });
+            }
+
+            ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
+                self.with_scope(item.id, |this| {
+                    visit::walk_item(this, item);
+                });
+            }
+
+            ItemKind::Static(ref ty, _, ref expr) |
+            ItemKind::Const(ref ty, ref expr) => {
+                debug!("resolve_item ItemKind::Const");
+                self.with_item_rib(|this| {
+                    this.visit_ty(ty);
+                    this.with_constant_rib(|this| {
+                        this.visit_expr(expr);
+                    });
+                });
+            }
+
+            ItemKind::Use(ref use_tree) => {
+                self.future_proof_import(use_tree);
+            }
+
+            ItemKind::ExternCrate(..) |
+            ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
+                // do nothing, these are just around to be encoded
+            }
+
+            ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
+        }
+    }
+
+    fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        debug!("with_generic_param_rib");
+        match generic_params {
+            HasGenericParams(generics, rib_kind) => {
+                let mut function_type_rib = Rib::new(rib_kind);
+                let mut function_value_rib = Rib::new(rib_kind);
+                let mut seen_bindings = FxHashMap::default();
+                for param in &generics.params {
+                    match param.kind {
+                        GenericParamKind::Lifetime { .. } => {}
+                        GenericParamKind::Type { .. } => {
+                            let ident = param.ident.modern();
+                            debug!("with_generic_param_rib: {}", param.id);
+
+                            if seen_bindings.contains_key(&ident) {
+                                let span = seen_bindings.get(&ident).unwrap();
+                                let err = ResolutionError::NameAlreadyUsedInParameterList(
+                                    ident.name,
+                                    *span,
+                                );
+                                resolve_error(self, param.ident.span, err);
+                            }
+                            seen_bindings.entry(ident).or_insert(param.ident.span);
+
+                            // Plain insert (no renaming).
+                            let res = Res::Def(
+                                DefKind::TyParam,
+                                self.definitions.local_def_id(param.id),
+                            );
+                            function_type_rib.bindings.insert(ident, res);
+                            self.record_partial_res(param.id, PartialRes::new(res));
+                        }
+                        GenericParamKind::Const { .. } => {
+                            let ident = param.ident.modern();
+                            debug!("with_generic_param_rib: {}", param.id);
+
+                            if seen_bindings.contains_key(&ident) {
+                                let span = seen_bindings.get(&ident).unwrap();
+                                let err = ResolutionError::NameAlreadyUsedInParameterList(
+                                    ident.name,
+                                    *span,
+                                );
+                                resolve_error(self, param.ident.span, err);
+                            }
+                            seen_bindings.entry(ident).or_insert(param.ident.span);
+
+                            let res = Res::Def(
+                                DefKind::ConstParam,
+                                self.definitions.local_def_id(param.id),
+                            );
+                            function_value_rib.bindings.insert(ident, res);
+                            self.record_partial_res(param.id, PartialRes::new(res));
+                        }
+                    }
+                }
+                self.ribs[ValueNS].push(function_value_rib);
+                self.ribs[TypeNS].push(function_type_rib);
+            }
+
+            NoGenericParams => {
+                // Nothing to do.
+            }
+        }
+
+        f(self);
+
+        if let HasGenericParams(..) = generic_params {
+            self.ribs[TypeNS].pop();
+            self.ribs[ValueNS].pop();
+        }
+    }
+
+    fn with_label_rib<F>(&mut self, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        self.label_ribs.push(Rib::new(NormalRibKind));
+        f(self);
+        self.label_ribs.pop();
+    }
+
+    fn with_item_rib<F>(&mut self, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        self.ribs[ValueNS].push(Rib::new(ItemRibKind));
+        self.ribs[TypeNS].push(Rib::new(ItemRibKind));
+        f(self);
+        self.ribs[TypeNS].pop();
+        self.ribs[ValueNS].pop();
+    }
+
+    fn with_constant_rib<F>(&mut self, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        debug!("with_constant_rib");
+        self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
+        self.label_ribs.push(Rib::new(ConstantItemRibKind));
+        f(self);
+        self.label_ribs.pop();
+        self.ribs[ValueNS].pop();
+    }
+
+    fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
+    {
+        // Handle nested impls (inside fn bodies)
+        let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
+        let result = f(self);
+        self.current_self_type = previous_value;
+        result
+    }
+
+    fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
+    {
+        let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
+        let result = f(self);
+        self.current_self_item = previous_value;
+        result
+    }
+
+    /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
+    fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
+    {
+        let trait_assoc_types = replace(
+            &mut self.current_trait_assoc_types,
+            trait_items.iter().filter_map(|item| match &item.node {
+                TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
+                _ => None,
+            }).collect(),
+        );
+        let result = f(self);
+        self.current_trait_assoc_types = trait_assoc_types;
+        result
+    }
+
+    /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
+    fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option<DefId>) -> T
+    {
+        let mut new_val = None;
+        let mut new_id = None;
+        if let Some(trait_ref) = opt_trait_ref {
+            let path: Vec<_> = Segment::from_path(&trait_ref.path);
+            let res = self.smart_resolve_path_fragment(
+                trait_ref.ref_id,
+                None,
+                &path,
+                trait_ref.path.span,
+                PathSource::Trait(AliasPossibility::No),
+                CrateLint::SimplePath(trait_ref.ref_id),
+            ).base_res();
+            if res != Res::Err {
+                new_id = Some(res.def_id());
+                let span = trait_ref.path.span;
+                if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
+                    self.resolve_path(
+                        &path,
+                        Some(TypeNS),
+                        false,
+                        span,
+                        CrateLint::SimplePath(trait_ref.ref_id),
+                    )
+                {
+                    new_val = Some((module, trait_ref.clone()));
+                }
+            }
+        }
+        let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
+        let result = f(self, new_id);
+        self.current_trait_ref = original_trait_ref;
+        result
+    }
+
+    fn with_self_rib<F>(&mut self, self_res: Res, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        let mut self_type_rib = Rib::new(NormalRibKind);
+
+        // Plain insert (no renaming, since types are not currently hygienic)
+        self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
+        self.ribs[TypeNS].push(self_type_rib);
+        f(self);
+        self.ribs[TypeNS].pop();
+    }
+
+    fn with_self_struct_ctor_rib<F>(&mut self, impl_id: DefId, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        let self_res = Res::SelfCtor(impl_id);
+        let mut self_type_rib = Rib::new(NormalRibKind);
+        self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
+        self.ribs[ValueNS].push(self_type_rib);
+        f(self);
+        self.ribs[ValueNS].pop();
+    }
+
+    fn resolve_implementation(&mut self,
+                              generics: &Generics,
+                              opt_trait_reference: &Option<TraitRef>,
+                              self_type: &Ty,
+                              item_id: NodeId,
+                              impl_items: &[ImplItem]) {
+        debug!("resolve_implementation");
+        // If applicable, create a rib for the type parameters.
+        self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+            // Dummy self type for better errors if `Self` is used in the trait path.
+            this.with_self_rib(Res::SelfTy(None, None), |this| {
+                // Resolve the trait reference, if necessary.
+                this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
+                    let item_def_id = this.definitions.local_def_id(item_id);
+                    this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
+                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
+                            // Resolve type arguments in the trait path.
+                            visit::walk_trait_ref(this, trait_ref);
+                        }
+                        // Resolve the self type.
+                        this.visit_ty(self_type);
+                        // Resolve the generic parameters.
+                        this.visit_generics(generics);
+                        // Resolve the items within the impl.
+                        this.with_current_self_type(self_type, |this| {
+                            this.with_self_struct_ctor_rib(item_def_id, |this| {
+                                debug!("resolve_implementation with_self_struct_ctor_rib");
+                                for impl_item in impl_items {
+                                    this.resolver.resolve_visibility(
+                                        &impl_item.vis, &this.parent_scope()
+                                    );
+                                    // We also need a new scope for the impl item type parameters.
+                                    let generic_params = HasGenericParams(&impl_item.generics,
+                                                                          AssocItemRibKind);
+                                    this.with_generic_param_rib(generic_params, |this| {
+                                        use crate::ResolutionError::*;
+                                        match impl_item.node {
+                                            ImplItemKind::Const(..) => {
+                                                debug!(
+                                                    "resolve_implementation ImplItemKind::Const",
+                                                );
+                                                // If this is a trait impl, ensure the const
+                                                // exists in trait
+                                                this.check_trait_item(
+                                                    impl_item.ident,
+                                                    ValueNS,
+                                                    impl_item.span,
+                                                    |n, s| ConstNotMemberOfTrait(n, s),
+                                                );
+
+                                                this.with_constant_rib(|this| {
+                                                    visit::walk_impl_item(this, impl_item)
+                                                });
+                                            }
+                                            ImplItemKind::Method(..) => {
+                                                // If this is a trait impl, ensure the method
+                                                // exists in trait
+                                                this.check_trait_item(impl_item.ident,
+                                                                      ValueNS,
+                                                                      impl_item.span,
+                                                    |n, s| MethodNotMemberOfTrait(n, s));
+
+                                                visit::walk_impl_item(this, impl_item);
+                                            }
+                                            ImplItemKind::TyAlias(ref ty) => {
+                                                // If this is a trait impl, ensure the type
+                                                // exists in trait
+                                                this.check_trait_item(impl_item.ident,
+                                                                      TypeNS,
+                                                                      impl_item.span,
+                                                    |n, s| TypeNotMemberOfTrait(n, s));
+
+                                                this.visit_ty(ty);
+                                            }
+                                            ImplItemKind::OpaqueTy(ref bounds) => {
+                                                // If this is a trait impl, ensure the type
+                                                // exists in trait
+                                                this.check_trait_item(impl_item.ident,
+                                                                      TypeNS,
+                                                                      impl_item.span,
+                                                    |n, s| TypeNotMemberOfTrait(n, s));
+
+                                                for bound in bounds {
+                                                    this.visit_param_bound(bound);
+                                                }
+                                            }
+                                            ImplItemKind::Macro(_) =>
+                                                panic!("unexpanded macro in resolve!"),
+                                        }
+                                    });
+                                }
+                            });
+                        });
+                    });
+                });
+            });
+        });
+    }
+
+    fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
+        where F: FnOnce(Name, &str) -> ResolutionError<'_>
+    {
+        // If there is a TraitRef in scope for an impl, then the method must be in the
+        // trait.
+        if let Some((module, _)) = self.current_trait_ref {
+            let parent_scope = &self.parent_scope();
+            if self.resolve_ident_in_module(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                parent_scope,
+                false,
+                span,
+            ).is_err() {
+                let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+                resolve_error(self, span, err(ident.name, &path_names_to_string(path)));
+            }
+        }
+    }
+
+    fn resolve_local(&mut self, local: &Local) {
+        // Resolve the type.
+        walk_list!(self, visit_ty, &local.ty);
+
+        // Resolve the initializer.
+        walk_list!(self, visit_expr, &local.init);
+
+        // Resolve the pattern.
+        self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default());
+    }
+
+    // build a map from pattern identifiers to binding-info's.
+    // this is done hygienically. This could arise for a macro
+    // that expands into an or-pattern where one 'x' was from the
+    // user and one 'x' came from the macro.
+    fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
+        let mut binding_map = FxHashMap::default();
+
+        pat.walk(&mut |pat| {
+            if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
+                if sub_pat.is_some() || match self.partial_res_map.get(&pat.id)
+                                                                  .map(|res| res.base_res()) {
+                    Some(Res::Local(..)) => true,
+                    _ => false,
+                } {
+                    let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
+                    binding_map.insert(ident, binding_info);
+                }
+            }
+            true
+        });
+
+        binding_map
+    }
+
+    // Checks that all of the arms in an or-pattern have exactly the
+    // same set of bindings, with the same binding modes for each.
+    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
+        if pats.is_empty() {
+            return;
+        }
+
+        let mut missing_vars = FxHashMap::default();
+        let mut inconsistent_vars = FxHashMap::default();
+        for (i, p) in pats.iter().enumerate() {
+            let map_i = self.binding_mode_map(&p);
+
+            for (j, q) in pats.iter().enumerate() {
+                if i == j {
+                    continue;
+                }
+
+                let map_j = self.binding_mode_map(&q);
+                for (&key, &binding_i) in &map_i {
+                    if map_j.is_empty() {                   // Account for missing bindings when
+                        let binding_error = missing_vars    // `map_j` has none.
+                            .entry(key.name)
+                            .or_insert(BindingError {
+                                name: key.name,
+                                origin: BTreeSet::new(),
+                                target: BTreeSet::new(),
+                            });
+                        binding_error.origin.insert(binding_i.span);
+                        binding_error.target.insert(q.span);
+                    }
+                    for (&key_j, &binding_j) in &map_j {
+                        match map_i.get(&key_j) {
+                            None => {  // missing binding
+                                let binding_error = missing_vars
+                                    .entry(key_j.name)
+                                    .or_insert(BindingError {
+                                        name: key_j.name,
+                                        origin: BTreeSet::new(),
+                                        target: BTreeSet::new(),
+                                    });
+                                binding_error.origin.insert(binding_j.span);
+                                binding_error.target.insert(p.span);
+                            }
+                            Some(binding_i) => {  // check consistent binding
+                                if binding_i.binding_mode != binding_j.binding_mode {
+                                    inconsistent_vars
+                                        .entry(key.name)
+                                        .or_insert((binding_j.span, binding_i.span));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
+        missing_vars.sort();
+        for (_, v) in missing_vars {
+            resolve_error(self,
+                          *v.origin.iter().next().unwrap(),
+                          ResolutionError::VariableNotBoundInPattern(v));
+        }
+        let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
+        inconsistent_vars.sort();
+        for (name, v) in inconsistent_vars {
+            resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
+        }
+    }
+
+    fn resolve_arm(&mut self, arm: &Arm) {
+        self.ribs[ValueNS].push(Rib::new(NormalRibKind));
+
+        self.resolve_pats(&arm.pats, PatternSource::Match);
+
+        if let Some(ref expr) = arm.guard {
+            self.visit_expr(expr)
+        }
+        self.visit_expr(&arm.body);
+
+        self.ribs[ValueNS].pop();
+    }
+
+    /// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
+    fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
+        let mut bindings_list = FxHashMap::default();
+        for pat in pats {
+            self.resolve_pattern(pat, source, &mut bindings_list);
+        }
+        // This has to happen *after* we determine which pat_idents are variants
+        self.check_consistent_bindings(pats);
+    }
+
+    fn resolve_block(&mut self, block: &Block) {
+        debug!("(resolving block) entering block");
+        // Move down in the graph, if there's an anonymous module rooted here.
+        let orig_module = self.current_module;
+        let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
+
+        let mut num_macro_definition_ribs = 0;
+        if let Some(anonymous_module) = anonymous_module {
+            debug!("(resolving block) found anonymous module, moving down");
+            self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
+            self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
+            self.current_module = anonymous_module;
+            self.finalize_current_module_macro_resolutions(anonymous_module);
+        } else {
+            self.ribs[ValueNS].push(Rib::new(NormalRibKind));
+        }
+
+        // Descend into the block.
+        for stmt in &block.stmts {
+            if let StmtKind::Item(ref item) = stmt.node {
+                if let ItemKind::MacroDef(..) = item.node {
+                    num_macro_definition_ribs += 1;
+                    let res = self.definitions.local_def_id(item.id);
+                    self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
+                    self.label_ribs.push(Rib::new(MacroDefinition(res)));
+                }
+            }
+
+            self.visit_stmt(stmt);
+        }
+
+        // Move back up.
+        self.current_module = orig_module;
+        for _ in 0 .. num_macro_definition_ribs {
+            self.ribs[ValueNS].pop();
+            self.label_ribs.pop();
+        }
+        self.ribs[ValueNS].pop();
+        if anonymous_module.is_some() {
+            self.ribs[TypeNS].pop();
+        }
+        debug!("(resolving block) leaving block");
+    }
+
+    fn fresh_binding(&mut self,
+                     ident: Ident,
+                     pat_id: NodeId,
+                     outer_pat_id: NodeId,
+                     pat_src: PatternSource,
+                     bindings: &mut FxHashMap<Ident, NodeId>)
+                     -> Res {
+        // Add the binding to the local ribs, if it
+        // doesn't already exist in the bindings map. (We
+        // must not add it if it's in the bindings map
+        // because that breaks the assumptions later
+        // passes make about or-patterns.)
+        let ident = ident.modern_and_legacy();
+        let mut res = Res::Local(pat_id);
+        match bindings.get(&ident).cloned() {
+            Some(id) if id == outer_pat_id => {
+                // `Variant(a, a)`, error
+                resolve_error(
+                    self,
+                    ident.span,
+                    ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
+                        &ident.as_str())
+                );
+            }
+            Some(..) if pat_src == PatternSource::FnParam => {
+                // `fn f(a: u8, a: u8)`, error
+                resolve_error(
+                    self,
+                    ident.span,
+                    ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
+                        &ident.as_str())
+                );
+            }
+            Some(..) if pat_src == PatternSource::Match ||
+                        pat_src == PatternSource::Let => {
+                // `Variant1(a) | Variant2(a)`, ok
+                // Reuse definition from the first `a`.
+                res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
+            }
+            Some(..) => {
+                span_bug!(ident.span, "two bindings with the same name from \
+                                       unexpected pattern source {:?}", pat_src);
+            }
+            None => {
+                // A completely fresh binding, add to the lists if it's valid.
+                if ident.name != kw::Invalid {
+                    bindings.insert(ident, outer_pat_id);
+                    self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res);
+                }
+            }
+        }
+
+        res
+    }
+
+    fn resolve_pattern(&mut self,
+                       pat: &Pat,
+                       pat_src: PatternSource,
+                       // Maps idents to the node ID for the
+                       // outermost pattern that binds them.
+                       bindings: &mut FxHashMap<Ident, NodeId>) {
+        // Visit all direct subpatterns of this pattern.
+        let outer_pat_id = pat.id;
+        pat.walk(&mut |pat| {
+            debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
+            match pat.node {
+                PatKind::Ident(bmode, ident, ref opt_pat) => {
+                    // First try to resolve the identifier as some existing
+                    // entity, then fall back to a fresh binding.
+                    let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS,
+                                                                      None, pat.span)
+                                      .and_then(LexicalScopeBinding::item);
+                    let res = binding.map(NameBinding::res).and_then(|res| {
+                        let is_syntactic_ambiguity = opt_pat.is_none() &&
+                            bmode == BindingMode::ByValue(Mutability::Immutable);
+                        match res {
+                            Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
+                            Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
+                                // Disambiguate in favor of a unit struct/variant
+                                // or constant pattern.
+                                self.record_use(ident, ValueNS, binding.unwrap(), false);
+                                Some(res)
+                            }
+                            Res::Def(DefKind::Ctor(..), _)
+                            | Res::Def(DefKind::Const, _)
+                            | Res::Def(DefKind::Static, _) => {
+                                // This is unambiguously a fresh binding, either syntactically
+                                // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
+                                // to something unusable as a pattern (e.g., constructor function),
+                                // but we still conservatively report an error, see
+                                // issues/33118#issuecomment-233962221 for one reason why.
+                                resolve_error(
+                                    self,
+                                    ident.span,
+                                    ResolutionError::BindingShadowsSomethingUnacceptable(
+                                        pat_src.descr(), ident.name, binding.unwrap())
+                                );
+                                None
+                            }
+                            Res::Def(DefKind::Fn, _) | Res::Err => {
+                                // These entities are explicitly allowed
+                                // to be shadowed by fresh bindings.
+                                None
+                            }
+                            res => {
+                                span_bug!(ident.span, "unexpected resolution for an \
+                                                       identifier in pattern: {:?}", res);
+                            }
+                        }
+                    }).unwrap_or_else(|| {
+                        self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
+                    });
+
+                    self.record_partial_res(pat.id, PartialRes::new(res));
+                }
+
+                PatKind::TupleStruct(ref path, ..) => {
+                    self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
+                }
+
+                PatKind::Path(ref qself, ref path) => {
+                    self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
+                }
+
+                PatKind::Struct(ref path, ..) => {
+                    self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
+                }
+
+                _ => {}
+            }
+            true
+        });
+
+        visit::walk_pat(self, pat);
+    }
+
+    // High-level and context dependent path resolution routine.
+    // Resolves the path and records the resolution into definition map.
+    // If resolution fails tries several techniques to find likely
+    // resolution candidates, suggest imports or other help, and report
+    // errors in user friendly way.
+    fn smart_resolve_path(&mut self,
+                          id: NodeId,
+                          qself: Option<&QSelf>,
+                          path: &Path,
+                          source: PathSource<'_>) {
+        self.smart_resolve_path_fragment(
+            id,
+            qself,
+            &Segment::from_path(path),
+            path.span,
+            source,
+            CrateLint::SimplePath(id),
+        );
+    }
+
+    fn smart_resolve_path_fragment(&mut self,
+                                   id: NodeId,
+                                   qself: Option<&QSelf>,
+                                   path: &[Segment],
+                                   span: Span,
+                                   source: PathSource<'_>,
+                                   crate_lint: CrateLint)
+                                   -> PartialRes {
+        let ns = source.namespace();
+        let is_expected = &|res| source.is_expected(res);
+
+        let report_errors = |this: &mut Self, res: Option<Res>| {
+            let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
+            let def_id = this.current_module.normal_ancestor_id;
+            let node_id = this.definitions.as_local_node_id(def_id).unwrap();
+            let better = res.is_some();
+            this.use_injections.push(UseError { err, candidates, node_id, better });
+            PartialRes::new(Res::Err)
+        };
+
+        let partial_res = match self.resolve_qpath_anywhere(
+            id,
+            qself,
+            path,
+            ns,
+            span,
+            source.defer_to_typeck(),
+            crate_lint,
+        ) {
+            Some(partial_res) if partial_res.unresolved_segments() == 0 => {
+                if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err {
+                    partial_res
+                } else {
+                    // Add a temporary hack to smooth the transition to new struct ctor
+                    // visibility rules. See #38932 for more details.
+                    let mut res = None;
+                    if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() {
+                        if let Some((ctor_res, ctor_vis))
+                                = self.struct_constructors.get(&def_id).cloned() {
+                            if is_expected(ctor_res) &&
+                               self.is_accessible_from(ctor_vis, self.current_module) {
+                                let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
+                                self.session.buffer_lint(lint, id, span,
+                                    "private struct constructors are not usable through \
+                                     re-exports in outer modules",
+                                );
+                                res = Some(PartialRes::new(ctor_res));
+                            }
+                        }
+                    }
+
+                    res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res())))
+                }
+            }
+            Some(partial_res) if source.defer_to_typeck() => {
+                // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
+                // or `<T>::A::B`. If `B` should be resolved in value namespace then
+                // it needs to be added to the trait map.
+                if ns == ValueNS {
+                    let item_name = path.last().unwrap().ident;
+                    let traits = self.get_traits_containing_item(item_name, ns);
+                    self.trait_map.insert(id, traits);
+                }
+
+                let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
+                std_path.extend(path);
+                if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
+                    let cl = CrateLint::No;
+                    let ns = Some(ns);
+                    if let PathResult::Module(_) | PathResult::NonModule(_) =
+                            self.resolve_path(&std_path, ns, false, span, cl) {
+                        // check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
+                        let item_span = path.iter().last().map(|segment| segment.ident.span)
+                            .unwrap_or(span);
+                        debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
+                        let mut hm = self.session.confused_type_with_std_module.borrow_mut();
+                        hm.insert(item_span, span);
+                        // In some places (E0223) we only have access to the full path
+                        hm.insert(span, span);
+                    }
+                }
+                partial_res
+            }
+            _ => report_errors(self, None)
+        };
+
+        if let PathSource::TraitItem(..) = source {} else {
+            // Avoid recording definition of `A::B` in `<T as A>::B::C`.
+            self.record_partial_res(id, partial_res);
+        }
+        partial_res
+    }
+
+    fn self_type_is_available(&mut self, span: Span) -> bool {
+        let binding = self.resolve_ident_in_lexical_scope(
+            Ident::with_empty_ctxt(kw::SelfUpper),
+            TypeNS,
+            None,
+            span,
+        );
+        if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
+    }
+
+    fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
+        let ident = Ident::new(kw::SelfLower, self_span);
+        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span);
+        if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
+    }
+
+    // Resolve in alternative namespaces if resolution in the primary namespace fails.
+    fn resolve_qpath_anywhere(
+        &mut self,
+        id: NodeId,
+        qself: Option<&QSelf>,
+        path: &[Segment],
+        primary_ns: Namespace,
+        span: Span,
+        defer_to_typeck: bool,
+        crate_lint: CrateLint,
+    ) -> Option<PartialRes> {
+        let mut fin_res = None;
+        for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
+            if i == 0 || ns != primary_ns {
+                match self.resolve_qpath(id, qself, path, ns, span, crate_lint) {
+                    // If defer_to_typeck, then resolution > no resolution,
+                    // otherwise full resolution > partial resolution > no resolution.
+                    Some(partial_res) if partial_res.unresolved_segments() == 0 ||
+                                         defer_to_typeck =>
+                        return Some(partial_res),
+                    partial_res => if fin_res.is_none() { fin_res = partial_res },
+                }
+            }
+        }
+
+        // `MacroNS`
+        assert!(primary_ns != MacroNS);
+        if qself.is_none() {
+            let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
+            let path = Path { segments: path.iter().map(path_seg).collect(), span };
+            let parent_scope = &self.parent_scope();
+            if let Ok((_, res)) =
+                    self.resolve_macro_path(&path, None, parent_scope, false, false) {
+                return Some(PartialRes::new(res));
+            }
+        }
+
+        fin_res
+    }
+
+    /// Handles paths that may refer to associated items.
+    fn resolve_qpath(
+        &mut self,
+        id: NodeId,
+        qself: Option<&QSelf>,
+        path: &[Segment],
+        ns: Namespace,
+        span: Span,
+        crate_lint: CrateLint,
+    ) -> Option<PartialRes> {
+        debug!(
+            "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})",
+            id,
+            qself,
+            path,
+            ns,
+            span,
+        );
+
+        if let Some(qself) = qself {
+            if qself.position == 0 {
+                // This is a case like `<T>::B`, where there is no
+                // trait to resolve.  In that case, we leave the `B`
+                // segment to be resolved by type-check.
+                return Some(PartialRes::with_unresolved_segments(
+                    Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len()
+                ));
+            }
+
+            // Make sure `A::B` in `<T as A::B>::C` is a trait item.
+            //
+            // Currently, `path` names the full item (`A::B::C`, in
+            // our example).  so we extract the prefix of that that is
+            // the trait (the slice upto and including
+            // `qself.position`). And then we recursively resolve that,
+            // but with `qself` set to `None`.
+            //
+            // However, setting `qself` to none (but not changing the
+            // span) loses the information about where this path
+            // *actually* appears, so for the purposes of the crate
+            // lint we pass along information that this is the trait
+            // name from a fully qualified path, and this also
+            // contains the full span (the `CrateLint::QPathTrait`).
+            let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
+            let partial_res = self.smart_resolve_path_fragment(
+                id,
+                None,
+                &path[..=qself.position],
+                span,
+                PathSource::TraitItem(ns),
+                CrateLint::QPathTrait {
+                    qpath_id: id,
+                    qpath_span: qself.path_span,
+                },
+            );
+
+            // The remaining segments (the `C` in our example) will
+            // have to be resolved by type-check, since that requires doing
+            // trait resolution.
+            return Some(PartialRes::with_unresolved_segments(
+                partial_res.base_res(),
+                partial_res.unresolved_segments() + path.len() - qself.position - 1,
+            ));
+        }
+
+        let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) {
+            PathResult::NonModule(path_res) => path_res,
+            PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
+                PartialRes::new(module.res().unwrap())
+            }
+            // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
+            // don't report an error right away, but try to fallback to a primitive type.
+            // So, we are still able to successfully resolve something like
+            //
+            // use std::u8; // bring module u8 in scope
+            // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
+            //     u8::max_value() // OK, resolves to associated function <u8>::max_value,
+            //                     // not to non-existent std::u8::max_value
+            // }
+            //
+            // Such behavior is required for backward compatibility.
+            // The same fallback is used when `a` resolves to nothing.
+            PathResult::Module(ModuleOrUniformRoot::Module(_)) |
+            PathResult::Failed { .. }
+                    if (ns == TypeNS || path.len() > 1) &&
+                       self.primitive_type_table.primitive_types
+                           .contains_key(&path[0].ident.name) => {
+                let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
+                PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
+            }
+            PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
+                PartialRes::new(module.res().unwrap()),
+            PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
+                resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
+                PartialRes::new(Res::Err)
+            }
+            PathResult::Module(..) | PathResult::Failed { .. } => return None,
+            PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
+        };
+
+        if path.len() > 1 && result.base_res() != Res::Err &&
+           path[0].ident.name != kw::PathRoot &&
+           path[0].ident.name != kw::DollarCrate {
+            let unqualified_result = {
+                match self.resolve_path(
+                    &[*path.last().unwrap()],
+                    Some(ns),
+                    false,
+                    span,
+                    CrateLint::No,
+                ) {
+                    PathResult::NonModule(path_res) => path_res.base_res(),
+                    PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
+                        module.res().unwrap(),
+                    _ => return Some(result),
+                }
+            };
+            if result.base_res() == unqualified_result {
+                let lint = lint::builtin::UNUSED_QUALIFICATIONS;
+                self.session.buffer_lint(lint, id, span, "unnecessary qualification")
+            }
+        }
+
+        Some(result)
+    }
+
+    fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
+        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
+    {
+        if let Some(label) = label {
+            self.unused_labels.insert(id, label.ident.span);
+            self.with_label_rib(|this| {
+                let ident = label.ident.modern_and_legacy();
+                this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
+                f(this);
+            });
+        } else {
+            f(self);
+        }
+    }
+
+    fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
+        self.with_resolved_label(label, id, |this| this.visit_block(block));
+    }
+
+    fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
+        // First, record candidate traits for this expression if it could
+        // result in the invocation of a method call.
+
+        self.record_candidate_traits_for_expr_if_necessary(expr);
+
+        // Next, resolve the node.
+        match expr.node {
+            ExprKind::Path(ref qself, ref path) => {
+                self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
+                visit::walk_expr(self, expr);
+            }
+
+            ExprKind::Struct(ref path, ..) => {
+                self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
+                visit::walk_expr(self, expr);
+            }
+
+            ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
+                let node_id = self.search_label(label.ident, |rib, ident| {
+                    rib.bindings.get(&ident.modern_and_legacy()).cloned()
+                });
+                match node_id {
+                    None => {
+                        // Search again for close matches...
+                        // Picks the first label that is "close enough", which is not necessarily
+                        // the closest match
+                        let close_match = self.search_label(label.ident, |rib, ident| {
+                            let names = rib.bindings.iter().filter_map(|(id, _)| {
+                                if id.span.ctxt() == label.ident.span.ctxt() {
+                                    Some(&id.name)
+                                } else {
+                                    None
+                                }
+                            });
+                            find_best_match_for_name(names, &*ident.as_str(), None)
+                        });
+                        self.record_partial_res(expr.id, PartialRes::new(Res::Err));
+                        resolve_error(self,
+                                      label.ident.span,
+                                      ResolutionError::UndeclaredLabel(&label.ident.as_str(),
+                                                                       close_match));
+                    }
+                    Some(node_id) => {
+                        // Since this res is a label, it is never read.
+                        self.label_res_map.insert(expr.id, node_id);
+                        self.unused_labels.remove(&node_id);
+                    }
+                }
+
+                // visit `break` argument if any
+                visit::walk_expr(self, expr);
+            }
+
+            ExprKind::Let(ref pats, ref scrutinee) => {
+                self.visit_expr(scrutinee);
+                self.resolve_pats(pats, PatternSource::Let);
+            }
+
+            ExprKind::If(ref cond, ref then, ref opt_else) => {
+                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
+                self.visit_expr(cond);
+                self.visit_block(then);
+                self.ribs[ValueNS].pop();
+
+                opt_else.as_ref().map(|expr| self.visit_expr(expr));
+            }
+
+            ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
+
+            ExprKind::While(ref subexpression, ref block, label) => {
+                self.with_resolved_label(label, expr.id, |this| {
+                    this.ribs[ValueNS].push(Rib::new(NormalRibKind));
+                    this.visit_expr(subexpression);
+                    this.visit_block(block);
+                    this.ribs[ValueNS].pop();
+                });
+            }
+
+            ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
+                self.visit_expr(subexpression);
+                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
+                self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default());
+
+                self.resolve_labeled_block(label, expr.id, block);
+
+                self.ribs[ValueNS].pop();
+            }
+
+            ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
+
+            // Equivalent to `visit::walk_expr` + passing some context to children.
+            ExprKind::Field(ref subexpression, _) => {
+                self.resolve_expr(subexpression, Some(expr));
+            }
+            ExprKind::MethodCall(ref segment, ref arguments) => {
+                let mut arguments = arguments.iter();
+                self.resolve_expr(arguments.next().unwrap(), Some(expr));
+                for argument in arguments {
+                    self.resolve_expr(argument, None);
+                }
+                self.visit_path_segment(expr.span, segment);
+            }
+
+            ExprKind::Call(ref callee, ref arguments) => {
+                self.resolve_expr(callee, Some(expr));
+                for argument in arguments {
+                    self.resolve_expr(argument, None);
+                }
+            }
+            ExprKind::Type(ref type_expr, _) => {
+                self.current_type_ascription.push(type_expr.span);
+                visit::walk_expr(self, expr);
+                self.current_type_ascription.pop();
+            }
+            // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
+            // resolve the arguments within the proper scopes so that usages of them inside the
+            // closure are detected as upvars rather than normal closure arg usages.
+            ExprKind::Closure(
+                _, IsAsync::Async { .. }, _,
+                ref fn_decl, ref body, _span,
+            ) => {
+                let rib_kind = NormalRibKind;
+                self.ribs[ValueNS].push(Rib::new(rib_kind));
+                // Resolve arguments:
+                let mut bindings_list = FxHashMap::default();
+                for argument in &fn_decl.inputs {
+                    self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
+                    self.visit_ty(&argument.ty);
+                }
+                // No need to resolve return type-- the outer closure return type is
+                // FunctionRetTy::Default
+
+                // Now resolve the inner closure
+                {
+                    // No need to resolve arguments: the inner closure has none.
+                    // Resolve the return type:
+                    visit::walk_fn_ret_ty(self, &fn_decl.output);
+                    // Resolve the body
+                    self.visit_expr(body);
+                }
+                self.ribs[ValueNS].pop();
+            }
+            _ => {
+                visit::walk_expr(self, expr);
+            }
+        }
+    }
+
+    fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
+        match expr.node {
+            ExprKind::Field(_, ident) => {
+                // FIXME(#6890): Even though you can't treat a method like a
+                // field, we need to add any trait methods we find that match
+                // the field name so that we can do some nice error reporting
+                // later on in typeck.
+                let traits = self.get_traits_containing_item(ident, ValueNS);
+                self.trait_map.insert(expr.id, traits);
+            }
+            ExprKind::MethodCall(ref segment, ..) => {
+                debug!("(recording candidate traits for expr) recording traits for {}",
+                       expr.id);
+                let traits = self.get_traits_containing_item(segment.ident, ValueNS);
+                self.trait_map.insert(expr.id, traits);
+            }
+            _ => {
+                // Nothing to do.
+            }
+        }
+    }
+
+    fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
+                                  -> Vec<TraitCandidate> {
+        debug!("(getting traits containing item) looking for '{}'", ident.name);
+
+        let mut found_traits = Vec::new();
+        // Look for the current trait.
+        if let Some((module, _)) = self.current_trait_ref {
+            let parent_scope = &self.parent_scope();
+            if self.resolve_ident_in_module(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                parent_scope,
+                false,
+                module.span,
+            ).is_ok() {
+                let def_id = module.def_id().unwrap();
+                found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
+            }
+        }
+
+        ident.span = ident.span.modern();
+        let mut search_module = self.current_module;
+        loop {
+            self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
+            search_module = unwrap_or!(
+                self.hygienic_lexical_parent(search_module, &mut ident.span), break
+            );
+        }
+
+        if let Some(prelude) = self.prelude {
+            if !search_module.no_implicit_prelude {
+                self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits);
+            }
+        }
+
+        found_traits
+    }
+
+    fn get_traits_in_module_containing_item(&mut self,
+                                            ident: Ident,
+                                            ns: Namespace,
+                                            module: Module<'a>,
+                                            found_traits: &mut Vec<TraitCandidate>) {
+        assert!(ns == TypeNS || ns == ValueNS);
+        let mut traits = module.traits.borrow_mut();
+        if traits.is_none() {
+            let mut collected_traits = Vec::new();
+            module.for_each_child(|name, ns, binding| {
+                if ns != TypeNS { return }
+                match binding.res() {
+                    Res::Def(DefKind::Trait, _) |
+                    Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)),
+                    _ => (),
+                }
+            });
+            *traits = Some(collected_traits.into_boxed_slice());
+        }
+
+        for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
+            // Traits have pseudo-modules that can be used to search for the given ident.
+            if let Some(module) = binding.module() {
+                let mut ident = ident;
+                if ident.span.glob_adjust(
+                    module.expansion,
+                    binding.span,
+                ).is_none() {
+                    continue
+                }
+                let parent_scope = &self.parent_scope();
+                if self.resolve_ident_in_module_unadjusted(
+                    ModuleOrUniformRoot::Module(module),
+                    ident,
+                    ns,
+                    parent_scope,
+                    false,
+                    module.span,
+                ).is_ok() {
+                    let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
+                    let trait_def_id = module.def_id().unwrap();
+                    found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
+                }
+            } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
+                // For now, just treat all trait aliases as possible candidates, since we don't
+                // know if the ident is somewhere in the transitive bounds.
+                let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
+                let trait_def_id = binding.res().def_id();
+                found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
+            } else {
+                bug!("candidate is not trait or trait alias?")
+            }
+        }
+    }
+
+    fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>,
+                               trait_name: Ident) -> SmallVec<[NodeId; 1]> {
+        let mut import_ids = smallvec![];
+        while let NameBindingKind::Import { directive, binding, .. } = kind {
+            self.maybe_unused_trait_imports.insert(directive.id);
+            self.add_to_glob_map(&directive, trait_name);
+            import_ids.push(directive.id);
+            kind = &binding.kind;
+        };
+        import_ids
+    }
+}
+
+impl<'a> Resolver<'a> {
+    pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
+        let mut late_resolution_visitor = LateResolutionVisitor::new(self);
+        let module = late_resolution_visitor.current_module;
+        late_resolution_visitor.finalize_current_module_macro_resolutions(module);
+        visit::walk_crate(&mut late_resolution_visitor, krate);
+        for (id, span) in late_resolution_visitor.unused_labels.iter() {
+            self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
+        }
+    }
+}
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
new file mode 100644
index 00000000000..ed76111bd58
--- /dev/null
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -0,0 +1,769 @@
+use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{PathResult, PathSource, RibKind, Segment};
+use crate::path_names_to_string;
+use crate::diagnostics::{add_typo_suggestion, add_module_candidates};
+use crate::diagnostics::{ImportSuggestion, TypoSuggestion};
+use crate::late::LateResolutionVisitor;
+
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use log::debug;
+use rustc::hir::def::{self, DefKind, CtorKind};
+use rustc::hir::def::Namespace::{self, *};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::PrimTy;
+use rustc::session::config::nightly_options;
+use rustc::util::nodemap::FxHashSet;
+use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
+use syntax::ext::base::MacroKind;
+use syntax::symbol::kw;
+use syntax::util::lev_distance::find_best_match_for_name;
+use syntax_pos::Span;
+
+type Res = def::Res<ast::NodeId>;
+
+/// A field or associated item from self type suggested in case of resolution failure.
+enum AssocSuggestion {
+    Field,
+    MethodWithSelf,
+    AssocItem,
+}
+
+fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
+    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
+}
+
+fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
+    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
+}
+
+/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
+fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
+    let variant_path = &suggestion.path;
+    let variant_path_string = path_names_to_string(variant_path);
+
+    let path_len = suggestion.path.segments.len();
+    let enum_path = ast::Path {
+        span: suggestion.path.span,
+        segments: suggestion.path.segments[0..path_len - 1].to_vec(),
+    };
+    let enum_path_string = path_names_to_string(&enum_path);
+
+    (variant_path_string, enum_path_string)
+}
+
+impl<'a> LateResolutionVisitor<'a, '_> {
+    /// Handles error reporting for `smart_resolve_path_fragment` function.
+    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
+    pub(crate) fn smart_resolve_report_errors(
+        &mut self,
+        path: &[Segment],
+        span: Span,
+        source: PathSource<'_>,
+        res: Option<Res>,
+    ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
+        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
+        let ns = source.namespace();
+        let is_expected = &|res| source.is_expected(res);
+        let is_enum_variant = &|res| {
+            if let Res::Def(DefKind::Variant, _) = res { true } else { false }
+        };
+
+        // Make the base error.
+        let expected = source.descr_expected();
+        let path_str = Segment::names_to_string(path);
+        let item_str = path.last().unwrap().ident;
+        let code = source.error_code(res.is_some());
+        let (base_msg, fallback_label, base_span) = if let Some(res) = res {
+            (format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
+                format!("not a {}", expected),
+                span)
+        } else {
+            let item_span = path.last().unwrap().ident.span;
+            let (mod_prefix, mod_str) = if path.len() == 1 {
+                (String::new(), "this scope".to_string())
+            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
+                (String::new(), "the crate root".to_string())
+            } else {
+                let mod_path = &path[..path.len() - 1];
+                let mod_prefix = match self.resolve_path(
+                    mod_path, Some(TypeNS), false, span, CrateLint::No
+                ) {
+                    PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
+                        module.def_kind(),
+                    _ => None,
+                }.map_or(String::new(), |kind| format!("{} ", kind.descr()));
+                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
+            };
+            (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
+                format!("not found in {}", mod_str),
+                item_span)
+        };
+
+        let code = DiagnosticId::Error(code.into());
+        let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code);
+
+        // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
+        if ["this", "my"].contains(&&*item_str.as_str())
+            && self.self_value_is_available(path[0].ident.span, span) {
+            err.span_suggestion(
+                span,
+                "did you mean",
+                "self".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+
+        // Emit special messages for unresolved `Self` and `self`.
+        if is_self_type(path, ns) {
+            __diagnostic_used!(E0411);
+            err.code(DiagnosticId::Error("E0411".into()));
+            err.span_label(span, format!("`Self` is only available in impls, traits, \
+                                          and type definitions"));
+            return (err, Vec::new());
+        }
+        if is_self_value(path, ns) {
+            debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
+
+            __diagnostic_used!(E0424);
+            err.code(DiagnosticId::Error("E0424".into()));
+            err.span_label(span, match source {
+                PathSource::Pat => {
+                    format!("`self` value is a keyword \
+                             and may not be bound to \
+                             variables or shadowed")
+                }
+                _ => {
+                    format!("`self` value is a keyword \
+                             only available in methods \
+                             with `self` parameter")
+                }
+            });
+            return (err, Vec::new());
+        }
+
+        // Try to lookup name in more relaxed fashion for better error reporting.
+        let ident = path.last().unwrap().ident;
+        let candidates = self.lookup_import_candidates(ident, ns, is_expected)
+            .drain(..)
+            .filter(|ImportSuggestion { did, .. }| {
+                match (did, res.and_then(|res| res.opt_def_id())) {
+                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
+                    _ => true,
+                }
+            })
+            .collect::<Vec<_>>();
+        let crate_def_id = DefId::local(CRATE_DEF_INDEX);
+        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
+            let enum_candidates =
+                self.lookup_import_candidates(ident, ns, is_enum_variant);
+            let mut enum_candidates = enum_candidates.iter()
+                .map(|suggestion| {
+                    import_candidate_to_enum_paths(&suggestion)
+                }).collect::<Vec<_>>();
+            enum_candidates.sort();
+
+            if !enum_candidates.is_empty() {
+                // Contextualize for E0412 "cannot find type", but don't belabor the point
+                // (that it's a variant) for E0573 "expected type, found variant".
+                let preamble = if res.is_none() {
+                    let others = match enum_candidates.len() {
+                        1 => String::new(),
+                        2 => " and 1 other".to_owned(),
+                        n => format!(" and {} others", n)
+                    };
+                    format!("there is an enum variant `{}`{}; ",
+                            enum_candidates[0].0, others)
+                } else {
+                    String::new()
+                };
+                let msg = format!("{}try using the variant's enum", preamble);
+
+                err.span_suggestions(
+                    span,
+                    &msg,
+                    enum_candidates.into_iter()
+                        .map(|(_variant_path, enum_ty_path)| enum_ty_path)
+                        // Variants re-exported in prelude doesn't mean `prelude::v1` is the
+                        // type name!
+                        // FIXME: is there a more principled way to do this that
+                        // would work for other re-exports?
+                        .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
+                        // Also write `Option` rather than `std::prelude::v1::Option`.
+                        .map(|enum_ty_path| {
+                            // FIXME #56861: DRY-er prelude filtering.
+                            enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
+                        }),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+        if path.len() == 1 && self.self_type_is_available(span) {
+            if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
+                let self_is_available = self.self_value_is_available(path[0].ident.span, span);
+                match candidate {
+                    AssocSuggestion::Field => {
+                        if self_is_available {
+                            err.span_suggestion(
+                                span,
+                                "you might have meant to use the available field",
+                                format!("self.{}", path_str),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.span_label(
+                                span,
+                                "a field by this name exists in `Self`",
+                            );
+                        }
+                    }
+                    AssocSuggestion::MethodWithSelf if self_is_available => {
+                        err.span_suggestion(
+                            span,
+                            "try",
+                            format!("self.{}", path_str),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
+                        err.span_suggestion(
+                            span,
+                            "try",
+                            format!("Self::{}", path_str),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                }
+                return (err, candidates);
+            }
+        }
+
+        // Try Levenshtein algorithm.
+        let levenshtein_worked = add_typo_suggestion(
+            &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span
+        );
+
+        // Try context-dependent help if relaxed lookup didn't work.
+        if let Some(res) = res {
+            if self.smart_resolve_context_dependent_help(&mut err,
+                                                         span,
+                                                         source,
+                                                         res,
+                                                         &path_str,
+                                                         &fallback_label) {
+                return (err, candidates);
+            }
+        }
+
+        // Fallback label.
+        if !levenshtein_worked {
+            err.span_label(base_span, fallback_label);
+            self.type_ascription_suggestion(&mut err, base_span);
+        }
+        (err, candidates)
+    }
+
+    fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) {
+        // HACK(estebank): find a better way to figure out that this was a
+        // parser issue where a struct literal is being used on an expression
+        // where a brace being opened means a block is being started. Look
+        // ahead for the next text to see if `span` is followed by a `{`.
+        let sm = self.session.source_map();
+        let mut sp = span;
+        loop {
+            sp = sm.next_point(sp);
+            match sm.span_to_snippet(sp) {
+                Ok(ref snippet) => {
+                    if snippet.chars().any(|c| { !c.is_whitespace() }) {
+                        break;
+                    }
+                }
+                _ => break,
+            }
+        }
+        let followed_by_brace = match sm.span_to_snippet(sp) {
+            Ok(ref snippet) if snippet == "{" => true,
+            _ => false,
+        };
+        // In case this could be a struct literal that needs to be surrounded
+        // by parenthesis, find the appropriate span.
+        let mut i = 0;
+        let mut closing_brace = None;
+        loop {
+            sp = sm.next_point(sp);
+            match sm.span_to_snippet(sp) {
+                Ok(ref snippet) => {
+                    if snippet == "}" {
+                        let sp = span.to(sp);
+                        if let Ok(snippet) = sm.span_to_snippet(sp) {
+                            closing_brace = Some((sp, snippet));
+                        }
+                        break;
+                    }
+                }
+                _ => break,
+            }
+            i += 1;
+            // The bigger the span, the more likely we're incorrect --
+            // bound it to 100 chars long.
+            if i > 100 {
+                break;
+            }
+        }
+        return (followed_by_brace, closing_brace)
+    }
+
+    /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
+    /// function.
+    /// Returns `true` if able to provide context-dependent help.
+    fn smart_resolve_context_dependent_help(
+        &mut self,
+        err: &mut DiagnosticBuilder<'a>,
+        span: Span,
+        source: PathSource<'_>,
+        res: Res,
+        path_str: &str,
+        fallback_label: &str,
+    ) -> bool {
+        let ns = source.namespace();
+        let is_expected = &|res| source.is_expected(res);
+
+        let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node {
+            ExprKind::Field(_, ident) => {
+                err.span_suggestion(
+                    expr.span,
+                    "use the path separator to refer to an item",
+                    format!("{}::{}", path_str, ident),
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
+            ExprKind::MethodCall(ref segment, ..) => {
+                let span = expr.span.with_hi(segment.ident.span.hi());
+                err.span_suggestion(
+                    span,
+                    "use the path separator to refer to an item",
+                    format!("{}::{}", path_str, segment.ident),
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
+            _ => false,
+        };
+
+        let mut bad_struct_syntax_suggestion = || {
+            let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
+            let mut suggested = false;
+            match source {
+                PathSource::Expr(Some(parent)) => {
+                    suggested = path_sep(err, &parent);
+                }
+                PathSource::Expr(None) if followed_by_brace == true => {
+                    if let Some((sp, snippet)) = closing_brace {
+                        err.span_suggestion(
+                            sp,
+                            "surround the struct literal with parenthesis",
+                            format!("({})", snippet),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.span_label(
+                            span,  // Note the parenthesis surrounding the suggestion below
+                            format!("did you mean `({} {{ /* fields */ }})`?", path_str),
+                        );
+                    }
+                    suggested = true;
+                },
+                _ => {}
+            }
+            if !suggested {
+                err.span_label(
+                    span,
+                    format!("did you mean `{} {{ /* fields */ }}`?", path_str),
+                );
+            }
+        };
+
+        match (res, source) {
+            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+                err.span_suggestion(
+                    span,
+                    "use `!` to invoke the macro",
+                    format!("{}!", path_str),
+                    Applicability::MaybeIncorrect,
+                );
+                if path_str == "try" && span.rust_2015() {
+                    err.note("if you want the `try` keyword, you need to be in the 2018 edition");
+                }
+            }
+            (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => {
+                err.span_label(span, "type aliases cannot be used as traits");
+                if nightly_options::is_nightly_build() {
+                    err.note("did you mean to use a trait alias?");
+                }
+            }
+            (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
+                if !path_sep(err, &parent) {
+                    return false;
+                }
+            }
+            (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct)
+                | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..))  => {
+                if let Some(variants) = self.collect_enum_variants(def_id) {
+                    if !variants.is_empty() {
+                        let msg = if variants.len() == 1 {
+                            "try using the enum's variant"
+                        } else {
+                            "try using one of the enum's variants"
+                        };
+
+                        err.span_suggestions(
+                            span,
+                            msg,
+                            variants.iter().map(path_names_to_string),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                } else {
+                    err.note("did you mean to use one of the enum's variants?");
+                }
+            },
+            (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
+                if let Some((ctor_def, ctor_vis))
+                        = self.struct_constructors.get(&def_id).cloned() {
+                    let accessible_ctor = self.is_accessible_from(ctor_vis, self.current_module);
+                    if is_expected(ctor_def) && !accessible_ctor {
+                        err.span_label(
+                            span,
+                            format!("constructor is not visible here due to private fields"),
+                        );
+                    }
+                } else {
+                    bad_struct_syntax_suggestion();
+                }
+            }
+            (Res::Def(DefKind::Union, _), _) |
+            (Res::Def(DefKind::Variant, _), _) |
+            (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => {
+                bad_struct_syntax_suggestion();
+            }
+            (Res::SelfTy(..), _) if ns == ValueNS => {
+                err.span_label(span, fallback_label);
+                err.note("can't use `Self` as a constructor, you must use the implemented struct");
+            }
+            (Res::Def(DefKind::TyAlias, _), _)
+            | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => {
+                err.note("can't use a type alias as a constructor");
+            }
+            _ => return false,
+        }
+        true
+    }
+
+    fn lookup_assoc_candidate<FilterFn>(&mut self,
+                                        ident: Ident,
+                                        ns: Namespace,
+                                        filter_fn: FilterFn)
+                                        -> Option<AssocSuggestion>
+        where FilterFn: Fn(Res) -> bool
+    {
+        fn extract_node_id(t: &Ty) -> Option<NodeId> {
+            match t.node {
+                TyKind::Path(None, _) => Some(t.id),
+                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
+                // This doesn't handle the remaining `Ty` variants as they are not
+                // that commonly the self_type, it might be interesting to provide
+                // support for those in future.
+                _ => None,
+            }
+        }
+
+        // Fields are generally expected in the same contexts as locals.
+        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
+            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
+                // Look for a field with the same name in the current self_type.
+                if let Some(resolution) = self.partial_res_map.get(&node_id) {
+                    match resolution.base_res() {
+                        Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did)
+                                if resolution.unresolved_segments() == 0 => {
+                            if let Some(field_names) = self.field_names.get(&did) {
+                                if field_names.iter().any(|&field_name| ident.name == field_name) {
+                                    return Some(AssocSuggestion::Field);
+                                }
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+        }
+
+        for assoc_type_ident in &self.current_trait_assoc_types {
+            if *assoc_type_ident == ident {
+                return Some(AssocSuggestion::AssocItem);
+            }
+        }
+
+        // Look for associated items in the current trait.
+        if let Some((module, _)) = self.current_trait_ref {
+            let parent_scope = &self.parent_scope();
+            if let Ok(binding) = self.resolve_ident_in_module(
+                    ModuleOrUniformRoot::Module(module),
+                    ident,
+                    ns,
+                    parent_scope,
+                    false,
+                    module.span,
+                ) {
+                let res = binding.res();
+                if filter_fn(res) {
+                    return Some(if self.has_self.contains(&res.def_id()) {
+                        AssocSuggestion::MethodWithSelf
+                    } else {
+                        AssocSuggestion::AssocItem
+                    });
+                }
+            }
+        }
+
+        None
+    }
+
+    fn lookup_typo_candidate(
+        &mut self,
+        path: &[Segment],
+        ns: Namespace,
+        filter_fn: &impl Fn(Res) -> bool,
+        span: Span,
+    ) -> Option<TypoSuggestion> {
+        let mut names = Vec::new();
+        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, &res) in &rib.bindings {
+                    if filter_fn(res) {
+                        names.push(TypoSuggestion::from_res(ident.name, res));
+                    }
+                }
+                // Items in scope
+                if let RibKind::ModuleRibKind(module) = rib.kind {
+                    // Items from this module
+                    add_module_candidates(module, &mut names, &filter_fn);
+
+                    if let ModuleKind::Block(..) = module.kind {
+                        // We can see through blocks
+                    } else {
+                        // Items from the prelude
+                        if !module.no_implicit_prelude {
+                            names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| {
+                                self.crate_loader
+                                    .maybe_process_path_extern(ident.name, ident.span)
+                                    .and_then(|crate_id| {
+                                        let crate_mod = Res::Def(
+                                            DefKind::Mod,
+                                            DefId {
+                                                krate: crate_id,
+                                                index: CRATE_DEF_INDEX,
+                                            },
+                                        );
+
+                                        if filter_fn(crate_mod) {
+                                            Some(TypoSuggestion::from_res(ident.name, crate_mod))
+                                        } else {
+                                            None
+                                        }
+                                    })
+                            }));
+
+                            if let Some(prelude) = self.prelude {
+                                add_module_candidates(prelude, &mut names, &filter_fn);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            // Add primitive types to the mix
+            if filter_fn(Res::PrimTy(PrimTy::Bool)) {
+                names.extend(
+                    self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
+                        TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
+                    })
+                )
+            }
+        } else {
+            // Search in module.
+            let mod_path = &path[..path.len() - 1];
+            if let PathResult::Module(module) = self.resolve_path(
+                mod_path, Some(TypeNS), false, span, CrateLint::No
+            ) {
+                if let ModuleOrUniformRoot::Module(module) = module {
+                    add_module_candidates(module, &mut names, &filter_fn);
+                }
+            }
+        }
+
+        let name = path[path.len() - 1].ident.name;
+        // Make sure error reporting is deterministic.
+        names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
+
+        match find_best_match_for_name(
+            names.iter().map(|suggestion| &suggestion.candidate),
+            &name.as_str(),
+            None,
+        ) {
+            Some(found) if found != name => names
+                .into_iter()
+                .find(|suggestion| suggestion.candidate == found),
+            _ => None,
+        }
+    }
+
+    /// Only used in a specific case of type ascription suggestions
+    fn get_colon_suggestion_span(&self, start: Span) -> Span {
+        let cm = self.session.source_map();
+        start.to(cm.next_point(start))
+    }
+
+    fn type_ascription_suggestion(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        base_span: Span,
+    ) {
+        debug!("type_ascription_suggetion {:?}", base_span);
+        let cm = self.session.source_map();
+        let base_snippet = cm.span_to_snippet(base_span);
+        debug!("self.current_type_ascription {:?}", self.current_type_ascription);
+        if let Some(sp) = self.current_type_ascription.last() {
+            let mut sp = *sp;
+            loop {
+                // Try to find the `:`; bail on first non-':' / non-whitespace.
+                sp = cm.next_point(sp);
+                if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
+                    let line_sp = cm.lookup_char_pos(sp.hi()).line;
+                    let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;
+                    if snippet == ":" {
+                        let mut show_label = true;
+                        if line_sp != line_base_sp {
+                            err.span_suggestion_short(
+                                sp,
+                                "did you mean to use `;` here instead?",
+                                ";".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            let colon_sp = self.get_colon_suggestion_span(sp);
+                            let after_colon_sp = self.get_colon_suggestion_span(
+                                colon_sp.shrink_to_hi(),
+                            );
+                            if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ")
+                                .unwrap_or(false)
+                            {
+                                err.span_suggestion(
+                                    colon_sp,
+                                    "maybe you meant to write a path separator here",
+                                    "::".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                show_label = false;
+                            }
+                            if let Ok(base_snippet) = base_snippet {
+                                let mut sp = after_colon_sp;
+                                for _ in 0..100 {
+                                    // Try to find an assignment
+                                    sp = cm.next_point(sp);
+                                    let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp)));
+                                    match snippet {
+                                        Ok(ref x) if x.as_str() == "=" => {
+                                            err.span_suggestion(
+                                                base_span,
+                                                "maybe you meant to write an assignment here",
+                                                format!("let {}", base_snippet),
+                                                Applicability::MaybeIncorrect,
+                                            );
+                                            show_label = false;
+                                            break;
+                                        }
+                                        Ok(ref x) if x.as_str() == "\n" => break,
+                                        Err(_) => break,
+                                        Ok(_) => {}
+                                    }
+                                }
+                            }
+                        }
+                        if show_label {
+                            err.span_label(base_span,
+                                           "expecting a type here because of type ascription");
+                        }
+                        break;
+                    } else if !snippet.trim().is_empty() {
+                        debug!("tried to find type ascription `:` token, couldn't find it");
+                        break;
+                    }
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
+        let mut result = None;
+        let mut seen_modules = FxHashSet::default();
+        let mut worklist = vec![(self.graph_root, Vec::new())];
+
+        while let Some((in_module, path_segments)) = worklist.pop() {
+            // abort if the module is already found
+            if result.is_some() { break; }
+
+            self.populate_module_if_necessary(in_module);
+
+            in_module.for_each_child_stable(|ident, _, name_binding| {
+                // abort if the module is already found or if name_binding is private external
+                if result.is_some() || !name_binding.vis.is_visible_locally() {
+                    return
+                }
+                if let Some(module) = name_binding.module() {
+                    // form the path
+                    let mut path_segments = path_segments.clone();
+                    path_segments.push(ast::PathSegment::from_ident(ident));
+                    let module_def_id = module.def_id().unwrap();
+                    if module_def_id == def_id {
+                        let path = Path {
+                            span: name_binding.span,
+                            segments: path_segments,
+                        };
+                        result = Some((module, ImportSuggestion { did: Some(def_id), path }));
+                    } else {
+                        // add the module to the lookup
+                        if seen_modules.insert(module_def_id) {
+                            worklist.push((module, path_segments));
+                        }
+                    }
+                }
+            });
+        }
+
+        result
+    }
+
+    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
+        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
+            self.populate_module_if_necessary(enum_module);
+
+            let mut variants = Vec::new();
+            enum_module.for_each_child_stable(|ident, _, name_binding| {
+                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
+                    let mut segms = enum_import_suggestion.path.segments.clone();
+                    segms.push(ast::PathSegment::from_ident(ident));
+                    variants.push(Path {
+                        span: name_binding.span,
+                        segments: segms,
+                    });
+                }
+            });
+            variants
+        })
+    }
+}
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e11413fcda9..8c099e4532c 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -13,9 +13,7 @@
 pub use rustc::hir::def::{Namespace, PerNS};
 
 use Determinacy::*;
-use GenericParameters::*;
 use RibKind::*;
-use smallvec::smallvec;
 
 use rustc::hir::map::Definitions;
 use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str};
@@ -27,7 +25,7 @@ use rustc::hir::def::{
 };
 use rustc::hir::def::Namespace::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
-use rustc::hir::{TraitCandidate, TraitMap, GlobMap};
+use rustc::hir::{TraitMap, GlobMap};
 use rustc::ty;
 use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
 use rustc::{bug, span_bug};
@@ -40,17 +38,12 @@ use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
 use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
 use syntax::symbol::{Symbol, kw, sym};
-use syntax::util::lev_distance::find_best_match_for_name;
 
-use syntax::visit::{self, FnKind, Visitor};
+use syntax::visit::{self, Visitor};
 use syntax::attr;
-use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
-use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
-use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
-use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
-use syntax::ast::{QSelf, TraitItem, TraitItemKind, TraitRef, Ty, TyKind};
-use syntax::ptr::P;
-use syntax::{struct_span_err, unwrap_or, walk_list};
+use syntax::ast::{CRATE_NODE_ID, Crate, Expr, ExprKind};
+use syntax::ast::{ItemKind, Path};
+use syntax::{span_err, struct_span_err, unwrap_or};
 
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
@@ -58,13 +51,10 @@ use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use log::debug;
 
 use std::cell::{Cell, RefCell};
-use std::{cmp, fmt, iter, mem, ptr};
-use std::ops::{Deref, DerefMut};
+use std::{cmp, fmt, iter, ptr};
 use std::collections::BTreeSet;
-use std::mem::replace;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
-use smallvec::SmallVec;
 
 use diagnostics::{Suggestion, ImportSuggestion};
 use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
@@ -77,6 +67,7 @@ type Res = def::Res<NodeId>;
 // registered before they are used.
 mod error_codes;
 mod diagnostics;
+mod late;
 mod macros;
 mod check_unused;
 mod build_reduced_graph;
@@ -488,34 +479,6 @@ fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
     impl_span
 }
 
-#[derive(Copy, Clone, Debug)]
-struct BindingInfo {
-    span: Span,
-    binding_mode: BindingMode,
-}
-
-/// Map from the name in a pattern to its binding mode.
-type BindingMap = FxHashMap<Ident, BindingInfo>;
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum PatternSource {
-    Match,
-    Let,
-    For,
-    FnParam,
-}
-
-impl PatternSource {
-    fn descr(self) -> &'static str {
-        match self {
-            PatternSource::Match => "match binding",
-            PatternSource::Let => "let binding",
-            PatternSource::For => "for binding",
-            PatternSource::FnParam => "function parameter",
-        }
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum AliasPossibility {
     No,
@@ -780,262 +743,6 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     }
 }
 
-struct LateResolutionVisitor<'a, 'b> {
-    resolver: &'b mut Resolver<'a>,
-
-    /// The module that represents the current item scope.
-    current_module: Module<'a>,
-
-    /// The current set of local scopes for types and values.
-    /// FIXME #4948: Reuse ribs to avoid allocation.
-    ribs: PerNS<Vec<Rib<'a>>>,
-
-    /// The current set of local scopes, for labels.
-    label_ribs: Vec<Rib<'a, NodeId>>,
-
-    /// The trait that the current context can refer to.
-    current_trait_ref: Option<(Module<'a>, TraitRef)>,
-
-    /// The current trait's associated types' ident, used for diagnostic suggestions.
-    current_trait_assoc_types: Vec<Ident>,
-
-    /// The current self type if inside an impl (used for better errors).
-    current_self_type: Option<Ty>,
-
-    /// The current self item if inside an ADT (used for better errors).
-    current_self_item: Option<NodeId>,
-
-    /// A list of labels as of yet unused. Labels will be removed from this map when
-    /// they are used (in a `break` or `continue` statement)
-    unused_labels: FxHashMap<NodeId, Span>,
-
-    /// Only used for better errors on `fn(): fn()`.
-    current_type_ascription: Vec<Span>,
-}
-
-impl<'a, 'b> LateResolutionVisitor<'a, '_> {
-    fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
-        let graph_root = resolver.graph_root;
-        LateResolutionVisitor {
-            resolver,
-            current_module: graph_root,
-            ribs: PerNS {
-                value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
-                type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
-                macro_ns: vec![Rib::new(ModuleRibKind(graph_root))],
-            },
-            label_ribs: Vec::new(),
-            current_trait_ref: None,
-            current_trait_assoc_types: Vec::new(),
-            current_self_type: None,
-            current_self_item: None,
-            unused_labels: Default::default(),
-            current_type_ascription: Vec::new(),
-        }
-    }
-
-    fn parent_scope(&self) -> ParentScope<'a> {
-        ParentScope { module: self.current_module, ..self.dummy_parent_scope() }
-    }
-}
-
-impl<'a> Deref for LateResolutionVisitor<'a, '_> {
-    type Target = Resolver<'a>;
-    fn deref(&self) -> &Self::Target {
-        self.resolver
-    }
-}
-
-impl<'a> DerefMut for LateResolutionVisitor<'a, '_> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.resolver
-    }
-}
-
-/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
-impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
-    fn visit_item(&mut self, item: &'tcx Item) {
-        self.resolve_item(item);
-    }
-    fn visit_arm(&mut self, arm: &'tcx Arm) {
-        self.resolve_arm(arm);
-    }
-    fn visit_block(&mut self, block: &'tcx Block) {
-        self.resolve_block(block);
-    }
-    fn visit_anon_const(&mut self, constant: &'tcx ast::AnonConst) {
-        debug!("visit_anon_const {:?}", constant);
-        self.with_constant_rib(|this| {
-            visit::walk_anon_const(this, constant);
-        });
-    }
-    fn visit_expr(&mut self, expr: &'tcx Expr) {
-        self.resolve_expr(expr, None);
-    }
-    fn visit_local(&mut self, local: &'tcx Local) {
-        self.resolve_local(local);
-    }
-    fn visit_ty(&mut self, ty: &'tcx Ty) {
-        match ty.node {
-            TyKind::Path(ref qself, ref path) => {
-                self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
-            }
-            TyKind::ImplicitSelf => {
-                let self_ty = Ident::with_empty_ctxt(kw::SelfUpper);
-                let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
-                              .map_or(Res::Err, |d| d.res());
-                self.record_partial_res(ty.id, PartialRes::new(res));
-            }
-            _ => (),
-        }
-        visit::walk_ty(self, ty);
-    }
-    fn visit_poly_trait_ref(&mut self,
-                            tref: &'tcx ast::PolyTraitRef,
-                            m: &'tcx ast::TraitBoundModifier) {
-        self.smart_resolve_path(tref.trait_ref.ref_id, None,
-                                &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
-        visit::walk_poly_trait_ref(self, tref, m);
-    }
-    fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
-        let generic_params = match foreign_item.node {
-            ForeignItemKind::Fn(_, ref generics) => {
-                HasGenericParams(generics, ItemRibKind)
-            }
-            ForeignItemKind::Static(..) => NoGenericParams,
-            ForeignItemKind::Ty => NoGenericParams,
-            ForeignItemKind::Macro(..) => NoGenericParams,
-        };
-        self.with_generic_param_rib(generic_params, |this| {
-            visit::walk_foreign_item(this, foreign_item);
-        });
-    }
-    fn visit_fn(&mut self,
-                function_kind: FnKind<'tcx>,
-                declaration: &'tcx FnDecl,
-                _: Span,
-                _: NodeId)
-    {
-        debug!("(resolving function) entering function");
-        let rib_kind = match function_kind {
-            FnKind::ItemFn(..) => FnItemRibKind,
-            FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
-        };
-
-        // Create a value rib for the function.
-        self.ribs[ValueNS].push(Rib::new(rib_kind));
-
-        // Create a label rib for the function.
-        self.label_ribs.push(Rib::new(rib_kind));
-
-        // Add each argument to the rib.
-        let mut bindings_list = FxHashMap::default();
-        for argument in &declaration.inputs {
-            self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
-
-            self.visit_ty(&argument.ty);
-
-            debug!("(resolving function) recorded argument");
-        }
-        visit::walk_fn_ret_ty(self, &declaration.output);
-
-        // Resolve the function body, potentially inside the body of an async closure
-        match function_kind {
-            FnKind::ItemFn(.., body) |
-            FnKind::Method(.., body) => {
-                self.visit_block(body);
-            }
-            FnKind::Closure(body) => {
-                self.visit_expr(body);
-            }
-        };
-
-        debug!("(resolving function) leaving function");
-
-        self.label_ribs.pop();
-        self.ribs[ValueNS].pop();
-    }
-
-    fn visit_generics(&mut self, generics: &'tcx Generics) {
-        // For type parameter defaults, we have to ban access
-        // to following type parameters, as the InternalSubsts can only
-        // provide previous type parameters as they're built. We
-        // put all the parameters on the ban list and then remove
-        // them one by one as they are processed and become available.
-        let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
-        let mut found_default = false;
-        default_ban_rib.bindings.extend(generics.params.iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Const { .. } |
-                GenericParamKind::Lifetime { .. } => None,
-                GenericParamKind::Type { ref default, .. } => {
-                    found_default |= default.is_some();
-                    if found_default {
-                        Some((Ident::with_empty_ctxt(param.ident.name), Res::Err))
-                    } else {
-                        None
-                    }
-                }
-            }));
-
-        // We also ban access to type parameters for use as the types of const parameters.
-        let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
-        const_ty_param_ban_rib.bindings.extend(generics.params.iter()
-            .filter(|param| {
-                if let GenericParamKind::Type { .. } = param.kind {
-                    true
-                } else {
-                    false
-                }
-            })
-            .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err)));
-
-        for param in &generics.params {
-            match param.kind {
-                GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
-                GenericParamKind::Type { ref default, .. } => {
-                    for bound in &param.bounds {
-                        self.visit_param_bound(bound);
-                    }
-
-                    if let Some(ref ty) = default {
-                        self.ribs[TypeNS].push(default_ban_rib);
-                        self.visit_ty(ty);
-                        default_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                    }
-
-                    // Allow all following defaults to refer to this type parameter.
-                    default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
-                }
-                GenericParamKind::Const { ref ty } => {
-                    self.ribs[TypeNS].push(const_ty_param_ban_rib);
-
-                    for bound in &param.bounds {
-                        self.visit_param_bound(bound);
-                    }
-
-                    self.visit_ty(ty);
-
-                    const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                }
-            }
-        }
-        for p in &generics.where_clause.predicates {
-            self.visit_where_predicate(p);
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-enum GenericParameters<'a, 'b> {
-    NoGenericParams,
-    HasGenericParams(// Type parameters.
-                      &'b Generics,
-
-                      // The kind of the rib used for type parameters.
-                      RibKind<'a>),
-}
-
 /// The rib kind restricts certain accesses,
 /// e.g. to a `Res::Local` of an outer item.
 #[derive(Copy, Clone, Debug)]
@@ -1854,76 +1561,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
 }
 
 impl<'a> Resolver<'a> {
-    /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
-    /// isn't something that can be returned because it can't be made to live that long,
-    /// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
-    /// just that an error occurred.
-    pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool)
-        -> Result<(ast::Path, Res), ()> {
-        let path = if path_str.starts_with("::") {
-            ast::Path {
-                span,
-                segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot))
-                    .chain({
-                        path_str.split("::").skip(1).map(Ident::from_str)
-                    })
-                    .map(|i| self.new_ast_path_segment(i))
-                    .collect(),
-            }
-        } else {
-            ast::Path {
-                span,
-                segments: path_str
-                    .split("::")
-                    .map(Ident::from_str)
-                    .map(|i| self.new_ast_path_segment(i))
-                    .collect(),
-            }
-        };
-        let res = self.resolve_ast_path_inner(&path, is_value).map_err(|_| ())?;
-        Ok((path, res))
-    }
-
-    /// Like `resolve_ast_path`, but takes a callback in case there was an error.
-    fn resolve_ast_path_inner(
-        &mut self,
-        path: &ast::Path,
-        is_value: bool,
-    ) -> Result<Res, (Span, ResolutionError<'a>)> {
-        let namespace = if is_value { ValueNS } else { TypeNS };
-        let span = path.span;
-        let path = Segment::from_path(&path);
-        // FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
-        let parent_scope = &self.dummy_parent_scope();
-        match self.resolve_path(&path, Some(namespace), parent_scope, true, span, CrateLint::No) {
-            PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
-                Ok(module.res().unwrap()),
-            PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
-                Ok(path_res.base_res()),
-            PathResult::NonModule(..) => {
-                Err((span, ResolutionError::FailedToResolve {
-                    label: String::from("type-relative paths are not supported in this context"),
-                    suggestion: None,
-                }))
-            }
-            PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
-            PathResult::Failed { span, label, suggestion, .. } => {
-                Err((span, ResolutionError::FailedToResolve {
-                    label,
-                    suggestion,
-                }))
-            }
-        }
-    }
-
-    fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
-        let mut seg = ast::PathSegment::from_ident(ident);
-        seg.id = self.session.next_node_id();
-        seg
-    }
-}
-
-impl<'a> Resolver<'a> {
     pub fn new(session: &'a Session,
                cstore: &'a CStore,
                krate: &Crate,
@@ -2097,12 +1734,7 @@ impl<'a> Resolver<'a> {
     pub fn resolve_crate(&mut self, krate: &Crate) {
         ImportResolver { resolver: self }.finalize_imports();
 
-        self.finalize_current_module_macro_resolutions(self.graph_root);
-        let mut late_resolution_visitor = LateResolutionVisitor::new(self);
-        visit::walk_crate(&mut late_resolution_visitor, krate);
-        for (id, span) in late_resolution_visitor.unused_labels.iter() {
-            self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
-        }
+        self.late_resolve_crate(krate);
 
         check_unused::check_crate(self, krate);
         self.report_errors(krate);
@@ -2297,9 +1929,7 @@ impl<'a> Resolver<'a> {
 
         None
     }
-}
 
-impl<'a> Resolver<'a> {
     /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
     /// More specifically, we proceed up the hierarchy of scopes and return the binding for
     /// `ident` in the first scope that defines it (or None if no scopes define it).
@@ -2605,1283 +2235,7 @@ impl<'a> Resolver<'a> {
         }
         module
     }
-}
-
-impl<'a> LateResolutionVisitor<'a, '_> {
-    // AST resolution
-    //
-    // We maintain a list of value ribs and type ribs.
-    //
-    // Simultaneously, we keep track of the current position in the module
-    // graph in the `current_module` pointer. When we go to resolve a name in
-    // the value or type namespaces, we first look through all the ribs and
-    // then query the module graph. When we resolve a name in the module
-    // namespace, we can skip all the ribs (since nested modules are not
-    // allowed within blocks in Rust) and jump straight to the current module
-    // graph node.
-    //
-    // Named implementations are handled separately. When we find a method
-    // call, we consult the module node to find all of the implementations in
-    // scope. This information is lazily cached in the module node. We then
-    // generate a fake "implementation scope" containing all the
-    // implementations thus found, for compatibility with old resolve pass.
-
-    fn resolve_ident_in_lexical_scope(&mut self,
-                                      ident: Ident,
-                                      ns: Namespace,
-                                      record_used_id: Option<NodeId>,
-                                      path_span: Span)
-                                      -> Option<LexicalScopeBinding<'a>> {
-        self.resolver.resolve_ident_in_lexical_scope(
-            ident, ns, &self.parent_scope(), record_used_id, path_span, &self.ribs[ns]
-        )
-    }
-
-    fn resolve_path(
-        &mut self,
-        path: &[Segment],
-        opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        record_used: bool,
-        path_span: Span,
-        crate_lint: CrateLint,
-    ) -> PathResult<'a> {
-        self.resolver.resolve_path_with_ribs(
-            path, opt_ns, &self.parent_scope(), record_used, path_span, crate_lint, &self.ribs
-        )
-    }
-
-    pub fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
-    {
-        let id = self.definitions.local_def_id(id);
-        let module = self.module_map.get(&id).cloned(); // clones a reference
-        if let Some(module) = module {
-            // Move down in the graph.
-            let orig_module = replace(&mut self.current_module, module);
-            self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
-            self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
-
-            self.resolver.finalize_current_module_macro_resolutions(self.current_module);
-            let ret = f(self);
-
-            self.current_module = orig_module;
-            self.ribs[ValueNS].pop();
-            self.ribs[TypeNS].pop();
-            ret
-        } else {
-            f(self)
-        }
-    }
-
-    /// Searches the current set of local scopes for labels. Returns the first non-`None` label that
-    /// is returned by the given predicate function
-    ///
-    /// Stops after meeting a closure.
-    fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
-        where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R>
-    {
-        for rib in self.label_ribs.iter().rev() {
-            match rib.kind {
-                NormalRibKind => {}
-                // If an invocation of this macro created `ident`, give up on `ident`
-                // and switch to `ident`'s source from the macro definition.
-                MacroDefinition(def) => {
-                    if def == self.macro_def(ident.span.ctxt()) {
-                        ident.span.remove_mark();
-                    }
-                }
-                _ => {
-                    // Do not resolve labels across function boundary
-                    return None;
-                }
-            }
-            let r = pred(rib, ident);
-            if r.is_some() {
-                return r;
-            }
-        }
-        None
-    }
-
-    fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
-        debug!("resolve_adt");
-        self.with_current_self_item(item, |this| {
-            this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
-                let item_def_id = this.definitions.local_def_id(item.id);
-                this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
-                    visit::walk_item(this, item);
-                });
-            });
-        });
-    }
-
-    fn future_proof_import(&mut self, use_tree: &ast::UseTree) {
-        let segments = &use_tree.prefix.segments;
-        if !segments.is_empty() {
-            let ident = segments[0].ident;
-            if ident.is_path_segment_keyword() || ident.span.rust_2015() {
-                return;
-            }
-
-            let nss = match use_tree.kind {
-                ast::UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
-                _ => &[TypeNS],
-            };
-            let report_error = |this: &Self, ns| {
-                let what = if ns == TypeNS { "type parameters" } else { "local variables" };
-                this.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
-            };
-
-            for &ns in nss {
-                match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
-                    Some(LexicalScopeBinding::Res(..)) => {
-                        report_error(self, ns);
-                    }
-                    Some(LexicalScopeBinding::Item(binding)) => {
-                        let orig_blacklisted_binding =
-                            mem::replace(&mut self.blacklisted_binding, Some(binding));
-                        if let Some(LexicalScopeBinding::Res(..)) =
-                                self.resolve_ident_in_lexical_scope(ident, ns, None,
-                                                                    use_tree.prefix.span) {
-                            report_error(self, ns);
-                        }
-                        self.blacklisted_binding = orig_blacklisted_binding;
-                    }
-                    None => {}
-                }
-            }
-        } else if let ast::UseTreeKind::Nested(use_trees) = &use_tree.kind {
-            for (use_tree, _) in use_trees {
-                self.future_proof_import(use_tree);
-            }
-        }
-    }
-
-    fn resolve_item(&mut self, item: &Item) {
-        let name = item.ident.name;
-        debug!("(resolving item) resolving {} ({:?})", name, item.node);
-
-        match item.node {
-            ItemKind::TyAlias(_, ref generics) |
-            ItemKind::OpaqueTy(_, ref generics) |
-            ItemKind::Fn(_, _, ref generics, _) => {
-                self.with_generic_param_rib(
-                    HasGenericParams(generics, ItemRibKind),
-                    |this| visit::walk_item(this, item)
-                );
-            }
-
-            ItemKind::Enum(_, ref generics) |
-            ItemKind::Struct(_, ref generics) |
-            ItemKind::Union(_, ref generics) => {
-                self.resolve_adt(item, generics);
-            }
-
-            ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
-                self.resolve_implementation(generics,
-                                            opt_trait_ref,
-                                            &self_type,
-                                            item.id,
-                                            impl_items),
-
-            ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
-                // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
-                    let local_def_id = this.definitions.local_def_id(item.id);
-                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-
-                        for trait_item in trait_items {
-                            this.with_trait_items(trait_items, |this| {
-                                let generic_params = HasGenericParams(
-                                    &trait_item.generics,
-                                    AssocItemRibKind,
-                                );
-                                this.with_generic_param_rib(generic_params, |this| {
-                                    match trait_item.node {
-                                        TraitItemKind::Const(ref ty, ref default) => {
-                                            this.visit_ty(ty);
-
-                                            // Only impose the restrictions of
-                                            // ConstRibKind for an actual constant
-                                            // expression in a provided default.
-                                            if let Some(ref expr) = *default{
-                                                this.with_constant_rib(|this| {
-                                                    this.visit_expr(expr);
-                                                });
-                                            }
-                                        }
-                                        TraitItemKind::Method(_, _) => {
-                                            visit::walk_trait_item(this, trait_item)
-                                        }
-                                        TraitItemKind::Type(..) => {
-                                            visit::walk_trait_item(this, trait_item)
-                                        }
-                                        TraitItemKind::Macro(_) => {
-                                            panic!("unexpanded macro in resolve!")
-                                        }
-                                    };
-                                });
-                            });
-                        }
-                    });
-                });
-            }
-
-            ItemKind::TraitAlias(ref generics, ref bounds) => {
-                // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
-                    let local_def_id = this.definitions.local_def_id(item.id);
-                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-                    });
-                });
-            }
-
-            ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
-                self.with_scope(item.id, |this| {
-                    visit::walk_item(this, item);
-                });
-            }
-
-            ItemKind::Static(ref ty, _, ref expr) |
-            ItemKind::Const(ref ty, ref expr) => {
-                debug!("resolve_item ItemKind::Const");
-                self.with_item_rib(|this| {
-                    this.visit_ty(ty);
-                    this.with_constant_rib(|this| {
-                        this.visit_expr(expr);
-                    });
-                });
-            }
-
-            ItemKind::Use(ref use_tree) => {
-                self.future_proof_import(use_tree);
-            }
-
-            ItemKind::ExternCrate(..) |
-            ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
-                // do nothing, these are just around to be encoded
-            }
-
-            ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
-        }
-    }
-
-    fn with_generic_param_rib<'b, F>(&'b mut self, generic_params: GenericParameters<'a, 'b>, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        debug!("with_generic_param_rib");
-        match generic_params {
-            HasGenericParams(generics, rib_kind) => {
-                let mut function_type_rib = Rib::new(rib_kind);
-                let mut function_value_rib = Rib::new(rib_kind);
-                let mut seen_bindings = FxHashMap::default();
-                for param in &generics.params {
-                    match param.kind {
-                        GenericParamKind::Lifetime { .. } => {}
-                        GenericParamKind::Type { .. } => {
-                            let ident = param.ident.modern();
-                            debug!("with_generic_param_rib: {}", param.id);
-
-                            if seen_bindings.contains_key(&ident) {
-                                let span = seen_bindings.get(&ident).unwrap();
-                                let err = ResolutionError::NameAlreadyUsedInParameterList(
-                                    ident.name,
-                                    *span,
-                                );
-                                resolve_error(self, param.ident.span, err);
-                            }
-                            seen_bindings.entry(ident).or_insert(param.ident.span);
-
-                            // Plain insert (no renaming).
-                            let res = Res::Def(
-                                DefKind::TyParam,
-                                self.definitions.local_def_id(param.id),
-                            );
-                            function_type_rib.bindings.insert(ident, res);
-                            self.record_partial_res(param.id, PartialRes::new(res));
-                        }
-                        GenericParamKind::Const { .. } => {
-                            let ident = param.ident.modern();
-                            debug!("with_generic_param_rib: {}", param.id);
-
-                            if seen_bindings.contains_key(&ident) {
-                                let span = seen_bindings.get(&ident).unwrap();
-                                let err = ResolutionError::NameAlreadyUsedInParameterList(
-                                    ident.name,
-                                    *span,
-                                );
-                                resolve_error(self, param.ident.span, err);
-                            }
-                            seen_bindings.entry(ident).or_insert(param.ident.span);
-
-                            let res = Res::Def(
-                                DefKind::ConstParam,
-                                self.definitions.local_def_id(param.id),
-                            );
-                            function_value_rib.bindings.insert(ident, res);
-                            self.record_partial_res(param.id, PartialRes::new(res));
-                        }
-                    }
-                }
-                self.ribs[ValueNS].push(function_value_rib);
-                self.ribs[TypeNS].push(function_type_rib);
-            }
-
-            NoGenericParams => {
-                // Nothing to do.
-            }
-        }
-
-        f(self);
-
-        if let HasGenericParams(..) = generic_params {
-            self.ribs[TypeNS].pop();
-            self.ribs[ValueNS].pop();
-        }
-    }
-
-    fn with_label_rib<F>(&mut self, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        self.label_ribs.push(Rib::new(NormalRibKind));
-        f(self);
-        self.label_ribs.pop();
-    }
-
-    fn with_item_rib<F>(&mut self, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        self.ribs[ValueNS].push(Rib::new(ItemRibKind));
-        self.ribs[TypeNS].push(Rib::new(ItemRibKind));
-        f(self);
-        self.ribs[TypeNS].pop();
-        self.ribs[ValueNS].pop();
-    }
-
-    fn with_constant_rib<F>(&mut self, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        debug!("with_constant_rib");
-        self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
-        self.label_ribs.push(Rib::new(ConstantItemRibKind));
-        f(self);
-        self.label_ribs.pop();
-        self.ribs[ValueNS].pop();
-    }
-
-    fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
-    {
-        // Handle nested impls (inside fn bodies)
-        let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
-        let result = f(self);
-        self.current_self_type = previous_value;
-        result
-    }
-
-    fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
-    {
-        let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
-        let result = f(self);
-        self.current_self_item = previous_value;
-        result
-    }
-
-    /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
-    fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
-    {
-        let trait_assoc_types = replace(
-            &mut self.current_trait_assoc_types,
-            trait_items.iter().filter_map(|item| match &item.node {
-                TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
-                _ => None,
-            }).collect(),
-        );
-        let result = f(self);
-        self.current_trait_assoc_types = trait_assoc_types;
-        result
-    }
-
-    /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
-    fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option<DefId>) -> T
-    {
-        let mut new_val = None;
-        let mut new_id = None;
-        if let Some(trait_ref) = opt_trait_ref {
-            let path: Vec<_> = Segment::from_path(&trait_ref.path);
-            let res = self.smart_resolve_path_fragment(
-                trait_ref.ref_id,
-                None,
-                &path,
-                trait_ref.path.span,
-                PathSource::Trait(AliasPossibility::No),
-                CrateLint::SimplePath(trait_ref.ref_id),
-            ).base_res();
-            if res != Res::Err {
-                new_id = Some(res.def_id());
-                let span = trait_ref.path.span;
-                if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                    self.resolve_path(
-                        &path,
-                        Some(TypeNS),
-                        false,
-                        span,
-                        CrateLint::SimplePath(trait_ref.ref_id),
-                    )
-                {
-                    new_val = Some((module, trait_ref.clone()));
-                }
-            }
-        }
-        let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
-        let result = f(self, new_id);
-        self.current_trait_ref = original_trait_ref;
-        result
-    }
-
-    fn with_self_rib<F>(&mut self, self_res: Res, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        let mut self_type_rib = Rib::new(NormalRibKind);
-
-        // Plain insert (no renaming, since types are not currently hygienic)
-        self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
-        self.ribs[TypeNS].push(self_type_rib);
-        f(self);
-        self.ribs[TypeNS].pop();
-    }
-
-    fn with_self_struct_ctor_rib<F>(&mut self, impl_id: DefId, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        let self_res = Res::SelfCtor(impl_id);
-        let mut self_type_rib = Rib::new(NormalRibKind);
-        self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
-        self.ribs[ValueNS].push(self_type_rib);
-        f(self);
-        self.ribs[ValueNS].pop();
-    }
-
-    fn resolve_implementation(&mut self,
-                              generics: &Generics,
-                              opt_trait_reference: &Option<TraitRef>,
-                              self_type: &Ty,
-                              item_id: NodeId,
-                              impl_items: &[ImplItem]) {
-        debug!("resolve_implementation");
-        // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
-            // Dummy self type for better errors if `Self` is used in the trait path.
-            this.with_self_rib(Res::SelfTy(None, None), |this| {
-                // Resolve the trait reference, if necessary.
-                this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                    let item_def_id = this.definitions.local_def_id(item_id);
-                    this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
-                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
-                            // Resolve type arguments in the trait path.
-                            visit::walk_trait_ref(this, trait_ref);
-                        }
-                        // Resolve the self type.
-                        this.visit_ty(self_type);
-                        // Resolve the generic parameters.
-                        this.visit_generics(generics);
-                        // Resolve the items within the impl.
-                        this.with_current_self_type(self_type, |this| {
-                            this.with_self_struct_ctor_rib(item_def_id, |this| {
-                                debug!("resolve_implementation with_self_struct_ctor_rib");
-                                for impl_item in impl_items {
-                                    this.resolver.resolve_visibility(
-                                        &impl_item.vis, &this.parent_scope()
-                                    );
-                                    // We also need a new scope for the impl item type parameters.
-                                    let generic_params = HasGenericParams(&impl_item.generics,
-                                                                          AssocItemRibKind);
-                                    this.with_generic_param_rib(generic_params, |this| {
-                                        use self::ResolutionError::*;
-                                        match impl_item.node {
-                                            ImplItemKind::Const(..) => {
-                                                debug!(
-                                                    "resolve_implementation ImplItemKind::Const",
-                                                );
-                                                // If this is a trait impl, ensure the const
-                                                // exists in trait
-                                                this.check_trait_item(
-                                                    impl_item.ident,
-                                                    ValueNS,
-                                                    impl_item.span,
-                                                    |n, s| ConstNotMemberOfTrait(n, s),
-                                                );
-
-                                                this.with_constant_rib(|this| {
-                                                    visit::walk_impl_item(this, impl_item)
-                                                });
-                                            }
-                                            ImplItemKind::Method(..) => {
-                                                // If this is a trait impl, ensure the method
-                                                // exists in trait
-                                                this.check_trait_item(impl_item.ident,
-                                                                      ValueNS,
-                                                                      impl_item.span,
-                                                    |n, s| MethodNotMemberOfTrait(n, s));
-
-                                                visit::walk_impl_item(this, impl_item);
-                                            }
-                                            ImplItemKind::TyAlias(ref ty) => {
-                                                // If this is a trait impl, ensure the type
-                                                // exists in trait
-                                                this.check_trait_item(impl_item.ident,
-                                                                      TypeNS,
-                                                                      impl_item.span,
-                                                    |n, s| TypeNotMemberOfTrait(n, s));
-
-                                                this.visit_ty(ty);
-                                            }
-                                            ImplItemKind::OpaqueTy(ref bounds) => {
-                                                // If this is a trait impl, ensure the type
-                                                // exists in trait
-                                                this.check_trait_item(impl_item.ident,
-                                                                      TypeNS,
-                                                                      impl_item.span,
-                                                    |n, s| TypeNotMemberOfTrait(n, s));
-
-                                                for bound in bounds {
-                                                    this.visit_param_bound(bound);
-                                                }
-                                            }
-                                            ImplItemKind::Macro(_) =>
-                                                panic!("unexpanded macro in resolve!"),
-                                        }
-                                    });
-                                }
-                            });
-                        });
-                    });
-                });
-            });
-        });
-    }
-
-    fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
-        where F: FnOnce(Name, &str) -> ResolutionError<'_>
-    {
-        // If there is a TraitRef in scope for an impl, then the method must be in the
-        // trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            let parent_scope = &self.parent_scope();
-            if self.resolve_ident_in_module(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                parent_scope,
-                false,
-                span,
-            ).is_err() {
-                let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                resolve_error(self, span, err(ident.name, &path_names_to_string(path)));
-            }
-        }
-    }
-
-    fn resolve_local(&mut self, local: &Local) {
-        // Resolve the type.
-        walk_list!(self, visit_ty, &local.ty);
-
-        // Resolve the initializer.
-        walk_list!(self, visit_expr, &local.init);
-
-        // Resolve the pattern.
-        self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default());
-    }
-
-    // build a map from pattern identifiers to binding-info's.
-    // this is done hygienically. This could arise for a macro
-    // that expands into an or-pattern where one 'x' was from the
-    // user and one 'x' came from the macro.
-    fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
-        let mut binding_map = FxHashMap::default();
-
-        pat.walk(&mut |pat| {
-            if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
-                if sub_pat.is_some() || match self.partial_res_map.get(&pat.id)
-                                                                  .map(|res| res.base_res()) {
-                    Some(Res::Local(..)) => true,
-                    _ => false,
-                } {
-                    let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
-                    binding_map.insert(ident, binding_info);
-                }
-            }
-            true
-        });
-
-        binding_map
-    }
-
-    // Checks that all of the arms in an or-pattern have exactly the
-    // same set of bindings, with the same binding modes for each.
-    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
-        if pats.is_empty() {
-            return;
-        }
-
-        let mut missing_vars = FxHashMap::default();
-        let mut inconsistent_vars = FxHashMap::default();
-        for (i, p) in pats.iter().enumerate() {
-            let map_i = self.binding_mode_map(&p);
-
-            for (j, q) in pats.iter().enumerate() {
-                if i == j {
-                    continue;
-                }
-
-                let map_j = self.binding_mode_map(&q);
-                for (&key, &binding_i) in &map_i {
-                    if map_j.is_empty() {                   // Account for missing bindings when
-                        let binding_error = missing_vars    // `map_j` has none.
-                            .entry(key.name)
-                            .or_insert(BindingError {
-                                name: key.name,
-                                origin: BTreeSet::new(),
-                                target: BTreeSet::new(),
-                            });
-                        binding_error.origin.insert(binding_i.span);
-                        binding_error.target.insert(q.span);
-                    }
-                    for (&key_j, &binding_j) in &map_j {
-                        match map_i.get(&key_j) {
-                            None => {  // missing binding
-                                let binding_error = missing_vars
-                                    .entry(key_j.name)
-                                    .or_insert(BindingError {
-                                        name: key_j.name,
-                                        origin: BTreeSet::new(),
-                                        target: BTreeSet::new(),
-                                    });
-                                binding_error.origin.insert(binding_j.span);
-                                binding_error.target.insert(p.span);
-                            }
-                            Some(binding_i) => {  // check consistent binding
-                                if binding_i.binding_mode != binding_j.binding_mode {
-                                    inconsistent_vars
-                                        .entry(key.name)
-                                        .or_insert((binding_j.span, binding_i.span));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
-        missing_vars.sort();
-        for (_, v) in missing_vars {
-            resolve_error(self,
-                          *v.origin.iter().next().unwrap(),
-                          ResolutionError::VariableNotBoundInPattern(v));
-        }
-        let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
-        inconsistent_vars.sort();
-        for (name, v) in inconsistent_vars {
-            resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
-        }
-    }
-
-    fn resolve_arm(&mut self, arm: &Arm) {
-        self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-
-        self.resolve_pats(&arm.pats, PatternSource::Match);
-
-        if let Some(ref expr) = arm.guard {
-            self.visit_expr(expr)
-        }
-        self.visit_expr(&arm.body);
-
-        self.ribs[ValueNS].pop();
-    }
-
-    /// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
-    fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
-        let mut bindings_list = FxHashMap::default();
-        for pat in pats {
-            self.resolve_pattern(pat, source, &mut bindings_list);
-        }
-        // This has to happen *after* we determine which pat_idents are variants
-        self.check_consistent_bindings(pats);
-    }
-
-    fn resolve_block(&mut self, block: &Block) {
-        debug!("(resolving block) entering block");
-        // Move down in the graph, if there's an anonymous module rooted here.
-        let orig_module = self.current_module;
-        let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
-
-        let mut num_macro_definition_ribs = 0;
-        if let Some(anonymous_module) = anonymous_module {
-            debug!("(resolving block) found anonymous module, moving down");
-            self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
-            self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
-            self.current_module = anonymous_module;
-            self.resolver.finalize_current_module_macro_resolutions(self.current_module);
-        } else {
-            self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-        }
-
-        // Descend into the block.
-        for stmt in &block.stmts {
-            if let ast::StmtKind::Item(ref item) = stmt.node {
-                if let ast::ItemKind::MacroDef(..) = item.node {
-                    num_macro_definition_ribs += 1;
-                    let res = self.definitions.local_def_id(item.id);
-                    self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
-                    self.label_ribs.push(Rib::new(MacroDefinition(res)));
-                }
-            }
-
-            self.visit_stmt(stmt);
-        }
-
-        // Move back up.
-        self.current_module = orig_module;
-        for _ in 0 .. num_macro_definition_ribs {
-            self.ribs[ValueNS].pop();
-            self.label_ribs.pop();
-        }
-        self.ribs[ValueNS].pop();
-        if anonymous_module.is_some() {
-            self.ribs[TypeNS].pop();
-        }
-        debug!("(resolving block) leaving block");
-    }
-
-    fn fresh_binding(&mut self,
-                     ident: Ident,
-                     pat_id: NodeId,
-                     outer_pat_id: NodeId,
-                     pat_src: PatternSource,
-                     bindings: &mut FxHashMap<Ident, NodeId>)
-                     -> Res {
-        // Add the binding to the local ribs, if it
-        // doesn't already exist in the bindings map. (We
-        // must not add it if it's in the bindings map
-        // because that breaks the assumptions later
-        // passes make about or-patterns.)
-        let ident = ident.modern_and_legacy();
-        let mut res = Res::Local(pat_id);
-        match bindings.get(&ident).cloned() {
-            Some(id) if id == outer_pat_id => {
-                // `Variant(a, a)`, error
-                resolve_error(
-                    self,
-                    ident.span,
-                    ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
-                        &ident.as_str())
-                );
-            }
-            Some(..) if pat_src == PatternSource::FnParam => {
-                // `fn f(a: u8, a: u8)`, error
-                resolve_error(
-                    self,
-                    ident.span,
-                    ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
-                        &ident.as_str())
-                );
-            }
-            Some(..) if pat_src == PatternSource::Match ||
-                        pat_src == PatternSource::Let => {
-                // `Variant1(a) | Variant2(a)`, ok
-                // Reuse definition from the first `a`.
-                res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
-            }
-            Some(..) => {
-                span_bug!(ident.span, "two bindings with the same name from \
-                                       unexpected pattern source {:?}", pat_src);
-            }
-            None => {
-                // A completely fresh binding, add to the lists if it's valid.
-                if ident.name != kw::Invalid {
-                    bindings.insert(ident, outer_pat_id);
-                    self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res);
-                }
-            }
-        }
-
-        res
-    }
-
-    fn resolve_pattern(&mut self,
-                       pat: &Pat,
-                       pat_src: PatternSource,
-                       // Maps idents to the node ID for the
-                       // outermost pattern that binds them.
-                       bindings: &mut FxHashMap<Ident, NodeId>) {
-        // Visit all direct subpatterns of this pattern.
-        let outer_pat_id = pat.id;
-        pat.walk(&mut |pat| {
-            debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
-            match pat.node {
-                PatKind::Ident(bmode, ident, ref opt_pat) => {
-                    // First try to resolve the identifier as some existing
-                    // entity, then fall back to a fresh binding.
-                    let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS,
-                                                                      None, pat.span)
-                                      .and_then(LexicalScopeBinding::item);
-                    let res = binding.map(NameBinding::res).and_then(|res| {
-                        let is_syntactic_ambiguity = opt_pat.is_none() &&
-                            bmode == BindingMode::ByValue(Mutability::Immutable);
-                        match res {
-                            Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
-                            Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
-                                // Disambiguate in favor of a unit struct/variant
-                                // or constant pattern.
-                                self.record_use(ident, ValueNS, binding.unwrap(), false);
-                                Some(res)
-                            }
-                            Res::Def(DefKind::Ctor(..), _)
-                            | Res::Def(DefKind::Const, _)
-                            | Res::Def(DefKind::Static, _) => {
-                                // This is unambiguously a fresh binding, either syntactically
-                                // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
-                                // to something unusable as a pattern (e.g., constructor function),
-                                // but we still conservatively report an error, see
-                                // issues/33118#issuecomment-233962221 for one reason why.
-                                resolve_error(
-                                    self,
-                                    ident.span,
-                                    ResolutionError::BindingShadowsSomethingUnacceptable(
-                                        pat_src.descr(), ident.name, binding.unwrap())
-                                );
-                                None
-                            }
-                            Res::Def(DefKind::Fn, _) | Res::Err => {
-                                // These entities are explicitly allowed
-                                // to be shadowed by fresh bindings.
-                                None
-                            }
-                            res => {
-                                span_bug!(ident.span, "unexpected resolution for an \
-                                                       identifier in pattern: {:?}", res);
-                            }
-                        }
-                    }).unwrap_or_else(|| {
-                        self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
-                    });
-
-                    self.record_partial_res(pat.id, PartialRes::new(res));
-                }
-
-                PatKind::TupleStruct(ref path, ..) => {
-                    self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
-                }
-
-                PatKind::Path(ref qself, ref path) => {
-                    self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
-                }
-
-                PatKind::Struct(ref path, ..) => {
-                    self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
-                }
-
-                _ => {}
-            }
-            true
-        });
-
-        visit::walk_pat(self, pat);
-    }
-
-    // High-level and context dependent path resolution routine.
-    // Resolves the path and records the resolution into definition map.
-    // If resolution fails tries several techniques to find likely
-    // resolution candidates, suggest imports or other help, and report
-    // errors in user friendly way.
-    fn smart_resolve_path(&mut self,
-                          id: NodeId,
-                          qself: Option<&QSelf>,
-                          path: &Path,
-                          source: PathSource<'_>) {
-        self.smart_resolve_path_fragment(
-            id,
-            qself,
-            &Segment::from_path(path),
-            path.span,
-            source,
-            CrateLint::SimplePath(id),
-        );
-    }
-
-    fn smart_resolve_path_fragment(&mut self,
-                                   id: NodeId,
-                                   qself: Option<&QSelf>,
-                                   path: &[Segment],
-                                   span: Span,
-                                   source: PathSource<'_>,
-                                   crate_lint: CrateLint)
-                                   -> PartialRes {
-        let ns = source.namespace();
-        let is_expected = &|res| source.is_expected(res);
-
-        let report_errors = |this: &mut Self, res: Option<Res>| {
-            let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
-            let def_id = this.current_module.normal_ancestor_id;
-            let node_id = this.definitions.as_local_node_id(def_id).unwrap();
-            let better = res.is_some();
-            this.use_injections.push(UseError { err, candidates, node_id, better });
-            PartialRes::new(Res::Err)
-        };
-
-        let partial_res = match self.resolve_qpath_anywhere(
-            id,
-            qself,
-            path,
-            ns,
-            span,
-            source.defer_to_typeck(),
-            crate_lint,
-        ) {
-            Some(partial_res) if partial_res.unresolved_segments() == 0 => {
-                if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err {
-                    partial_res
-                } else {
-                    // Add a temporary hack to smooth the transition to new struct ctor
-                    // visibility rules. See #38932 for more details.
-                    let mut res = None;
-                    if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() {
-                        if let Some((ctor_res, ctor_vis))
-                                = self.struct_constructors.get(&def_id).cloned() {
-                            if is_expected(ctor_res) &&
-                               self.is_accessible_from(ctor_vis, self.current_module) {
-                                let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
-                                self.session.buffer_lint(lint, id, span,
-                                    "private struct constructors are not usable through \
-                                     re-exports in outer modules",
-                                );
-                                res = Some(PartialRes::new(ctor_res));
-                            }
-                        }
-                    }
-
-                    res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res())))
-                }
-            }
-            Some(partial_res) if source.defer_to_typeck() => {
-                // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
-                // or `<T>::A::B`. If `B` should be resolved in value namespace then
-                // it needs to be added to the trait map.
-                if ns == ValueNS {
-                    let item_name = path.last().unwrap().ident;
-                    let traits = self.get_traits_containing_item(item_name, ns);
-                    self.trait_map.insert(id, traits);
-                }
-
-                let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
-                std_path.extend(path);
-                if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
-                    let cl = CrateLint::No;
-                    let ns = Some(ns);
-                    if let PathResult::Module(_) | PathResult::NonModule(_) =
-                            self.resolve_path(&std_path, ns, false, span, cl) {
-                        // check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
-                        let item_span = path.iter().last().map(|segment| segment.ident.span)
-                            .unwrap_or(span);
-                        debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
-                        let mut hm = self.session.confused_type_with_std_module.borrow_mut();
-                        hm.insert(item_span, span);
-                        // In some places (E0223) we only have access to the full path
-                        hm.insert(span, span);
-                    }
-                }
-                partial_res
-            }
-            _ => report_errors(self, None)
-        };
-
-        if let PathSource::TraitItem(..) = source {} else {
-            // Avoid recording definition of `A::B` in `<T as A>::B::C`.
-            self.record_partial_res(id, partial_res);
-        }
-        partial_res
-    }
-
-    /// Only used in a specific case of type ascription suggestions
-    #[doc(hidden)]
-    fn get_colon_suggestion_span(&self, start: Span) -> Span {
-        let cm = self.session.source_map();
-        start.to(cm.next_point(start))
-    }
-
-    fn type_ascription_suggestion(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        base_span: Span,
-    ) {
-        debug!("type_ascription_suggetion {:?}", base_span);
-        let cm = self.session.source_map();
-        let base_snippet = cm.span_to_snippet(base_span);
-        debug!("self.current_type_ascription {:?}", self.current_type_ascription);
-        if let Some(sp) = self.current_type_ascription.last() {
-            let mut sp = *sp;
-            loop {
-                // Try to find the `:`; bail on first non-':' / non-whitespace.
-                sp = cm.next_point(sp);
-                if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
-                    let line_sp = cm.lookup_char_pos(sp.hi()).line;
-                    let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;
-                    if snippet == ":" {
-                        let mut show_label = true;
-                        if line_sp != line_base_sp {
-                            err.span_suggestion_short(
-                                sp,
-                                "did you mean to use `;` here instead?",
-                                ";".to_string(),
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            let colon_sp = self.get_colon_suggestion_span(sp);
-                            let after_colon_sp = self.get_colon_suggestion_span(
-                                colon_sp.shrink_to_hi(),
-                            );
-                            if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ")
-                                .unwrap_or(false)
-                            {
-                                err.span_suggestion(
-                                    colon_sp,
-                                    "maybe you meant to write a path separator here",
-                                    "::".to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                show_label = false;
-                            }
-                            if let Ok(base_snippet) = base_snippet {
-                                let mut sp = after_colon_sp;
-                                for _ in 0..100 {
-                                    // Try to find an assignment
-                                    sp = cm.next_point(sp);
-                                    let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp)));
-                                    match snippet {
-                                        Ok(ref x) if x.as_str() == "=" => {
-                                            err.span_suggestion(
-                                                base_span,
-                                                "maybe you meant to write an assignment here",
-                                                format!("let {}", base_snippet),
-                                                Applicability::MaybeIncorrect,
-                                            );
-                                            show_label = false;
-                                            break;
-                                        }
-                                        Ok(ref x) if x.as_str() == "\n" => break,
-                                        Err(_) => break,
-                                        Ok(_) => {}
-                                    }
-                                }
-                            }
-                        }
-                        if show_label {
-                            err.span_label(base_span,
-                                           "expecting a type here because of type ascription");
-                        }
-                        break;
-                    } else if !snippet.trim().is_empty() {
-                        debug!("tried to find type ascription `:` token, couldn't find it");
-                        break;
-                    }
-                } else {
-                    break;
-                }
-            }
-        }
-    }
-
-    fn self_type_is_available(&mut self, span: Span) -> bool {
-        let binding = self.resolve_ident_in_lexical_scope(
-            Ident::with_empty_ctxt(kw::SelfUpper),
-            TypeNS,
-            None,
-            span,
-        );
-        if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
-    }
-
-    fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
-        let ident = Ident::new(kw::SelfLower, self_span);
-        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span);
-        if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
-    }
-
-    // Resolve in alternative namespaces if resolution in the primary namespace fails.
-    fn resolve_qpath_anywhere(
-        &mut self,
-        id: NodeId,
-        qself: Option<&QSelf>,
-        path: &[Segment],
-        primary_ns: Namespace,
-        span: Span,
-        defer_to_typeck: bool,
-        crate_lint: CrateLint,
-    ) -> Option<PartialRes> {
-        let mut fin_res = None;
-        for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
-            if i == 0 || ns != primary_ns {
-                match self.resolve_qpath(id, qself, path, ns, span, crate_lint) {
-                    // If defer_to_typeck, then resolution > no resolution,
-                    // otherwise full resolution > partial resolution > no resolution.
-                    Some(partial_res) if partial_res.unresolved_segments() == 0 ||
-                                         defer_to_typeck =>
-                        return Some(partial_res),
-                    partial_res => if fin_res.is_none() { fin_res = partial_res },
-                }
-            }
-        }
-
-        // `MacroNS`
-        assert!(primary_ns != MacroNS);
-        if qself.is_none() {
-            let path_seg = |seg: &Segment| ast::PathSegment::from_ident(seg.ident);
-            let path = Path { segments: path.iter().map(path_seg).collect(), span };
-            let parent_scope = &self.parent_scope();
-            if let Ok((_, res)) =
-                    self.resolve_macro_path(&path, None, parent_scope, false, false) {
-                return Some(PartialRes::new(res));
-            }
-        }
-
-        fin_res
-    }
-
-    /// Handles paths that may refer to associated items.
-    fn resolve_qpath(
-        &mut self,
-        id: NodeId,
-        qself: Option<&QSelf>,
-        path: &[Segment],
-        ns: Namespace,
-        span: Span,
-        crate_lint: CrateLint,
-    ) -> Option<PartialRes> {
-        debug!(
-            "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})",
-            id,
-            qself,
-            path,
-            ns,
-            span,
-        );
-
-        if let Some(qself) = qself {
-            if qself.position == 0 {
-                // This is a case like `<T>::B`, where there is no
-                // trait to resolve.  In that case, we leave the `B`
-                // segment to be resolved by type-check.
-                return Some(PartialRes::with_unresolved_segments(
-                    Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len()
-                ));
-            }
-
-            // Make sure `A::B` in `<T as A::B>::C` is a trait item.
-            //
-            // Currently, `path` names the full item (`A::B::C`, in
-            // our example).  so we extract the prefix of that that is
-            // the trait (the slice upto and including
-            // `qself.position`). And then we recursively resolve that,
-            // but with `qself` set to `None`.
-            //
-            // However, setting `qself` to none (but not changing the
-            // span) loses the information about where this path
-            // *actually* appears, so for the purposes of the crate
-            // lint we pass along information that this is the trait
-            // name from a fully qualified path, and this also
-            // contains the full span (the `CrateLint::QPathTrait`).
-            let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
-            let partial_res = self.smart_resolve_path_fragment(
-                id,
-                None,
-                &path[..=qself.position],
-                span,
-                PathSource::TraitItem(ns),
-                CrateLint::QPathTrait {
-                    qpath_id: id,
-                    qpath_span: qself.path_span,
-                },
-            );
-
-            // The remaining segments (the `C` in our example) will
-            // have to be resolved by type-check, since that requires doing
-            // trait resolution.
-            return Some(PartialRes::with_unresolved_segments(
-                partial_res.base_res(),
-                partial_res.unresolved_segments() + path.len() - qself.position - 1,
-            ));
-        }
-
-        let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) {
-            PathResult::NonModule(path_res) => path_res,
-            PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
-                PartialRes::new(module.res().unwrap())
-            }
-            // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
-            // don't report an error right away, but try to fallback to a primitive type.
-            // So, we are still able to successfully resolve something like
-            //
-            // use std::u8; // bring module u8 in scope
-            // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
-            //     u8::max_value() // OK, resolves to associated function <u8>::max_value,
-            //                     // not to non-existent std::u8::max_value
-            // }
-            //
-            // Such behavior is required for backward compatibility.
-            // The same fallback is used when `a` resolves to nothing.
-            PathResult::Module(ModuleOrUniformRoot::Module(_)) |
-            PathResult::Failed { .. }
-                    if (ns == TypeNS || path.len() > 1) &&
-                       self.primitive_type_table.primitive_types
-                           .contains_key(&path[0].ident.name) => {
-                let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
-                PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
-            }
-            PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
-                PartialRes::new(module.res().unwrap()),
-            PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
-                resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
-                PartialRes::new(Res::Err)
-            }
-            PathResult::Module(..) | PathResult::Failed { .. } => return None,
-            PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
-        };
-
-        if path.len() > 1 && result.base_res() != Res::Err &&
-           path[0].ident.name != kw::PathRoot &&
-           path[0].ident.name != kw::DollarCrate {
-            let unqualified_result = {
-                match self.resolve_path(
-                    &[*path.last().unwrap()],
-                    Some(ns),
-                    false,
-                    span,
-                    CrateLint::No,
-                ) {
-                    PathResult::NonModule(path_res) => path_res.base_res(),
-                    PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
-                        module.res().unwrap(),
-                    _ => return Some(result),
-                }
-            };
-            if result.base_res() == unqualified_result {
-                let lint = lint::builtin::UNUSED_QUALIFICATIONS;
-                self.session.buffer_lint(lint, id, span, "unnecessary qualification")
-            }
-        }
-
-        Some(result)
-    }
-}
 
-impl<'a> Resolver<'a> {
     fn resolve_path(
         &mut self,
         path: &[Segment],
@@ -4327,307 +2681,7 @@ impl<'a> Resolver<'a> {
         }
         res
     }
-}
-
-impl<'a> LateResolutionVisitor<'a, '_> {
-    fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
-        where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
-    {
-        if let Some(label) = label {
-            self.unused_labels.insert(id, label.ident.span);
-            self.with_label_rib(|this| {
-                let ident = label.ident.modern_and_legacy();
-                this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
-                f(this);
-            });
-        } else {
-            f(self);
-        }
-    }
-
-    fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
-        self.with_resolved_label(label, id, |this| this.visit_block(block));
-    }
-
-    fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
-        // First, record candidate traits for this expression if it could
-        // result in the invocation of a method call.
-
-        self.record_candidate_traits_for_expr_if_necessary(expr);
-
-        // Next, resolve the node.
-        match expr.node {
-            ExprKind::Path(ref qself, ref path) => {
-                self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
-                visit::walk_expr(self, expr);
-            }
-
-            ExprKind::Struct(ref path, ..) => {
-                self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
-                visit::walk_expr(self, expr);
-            }
-
-            ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                let node_id = self.search_label(label.ident, |rib, ident| {
-                    rib.bindings.get(&ident.modern_and_legacy()).cloned()
-                });
-                match node_id {
-                    None => {
-                        // Search again for close matches...
-                        // Picks the first label that is "close enough", which is not necessarily
-                        // the closest match
-                        let close_match = self.search_label(label.ident, |rib, ident| {
-                            let names = rib.bindings.iter().filter_map(|(id, _)| {
-                                if id.span.ctxt() == label.ident.span.ctxt() {
-                                    Some(&id.name)
-                                } else {
-                                    None
-                                }
-                            });
-                            find_best_match_for_name(names, &*ident.as_str(), None)
-                        });
-                        self.record_partial_res(expr.id, PartialRes::new(Res::Err));
-                        resolve_error(self,
-                                      label.ident.span,
-                                      ResolutionError::UndeclaredLabel(&label.ident.as_str(),
-                                                                       close_match));
-                    }
-                    Some(node_id) => {
-                        // Since this res is a label, it is never read.
-                        self.label_res_map.insert(expr.id, node_id);
-                        self.unused_labels.remove(&node_id);
-                    }
-                }
-
-                // visit `break` argument if any
-                visit::walk_expr(self, expr);
-            }
-
-            ExprKind::Let(ref pats, ref scrutinee) => {
-                self.visit_expr(scrutinee);
-                self.resolve_pats(pats, PatternSource::Let);
-            }
-
-            ExprKind::If(ref cond, ref then, ref opt_else) => {
-                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.visit_expr(cond);
-                self.visit_block(then);
-                self.ribs[ValueNS].pop();
-
-                opt_else.as_ref().map(|expr| self.visit_expr(expr));
-            }
-
-            ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
-
-            ExprKind::While(ref subexpression, ref block, label) => {
-                self.with_resolved_label(label, expr.id, |this| {
-                    this.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                    this.visit_expr(subexpression);
-                    this.visit_block(block);
-                    this.ribs[ValueNS].pop();
-                });
-            }
-
-            ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
-                self.visit_expr(subexpression);
-                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default());
-
-                self.resolve_labeled_block(label, expr.id, block);
-
-                self.ribs[ValueNS].pop();
-            }
-
-            ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
-
-            // Equivalent to `visit::walk_expr` + passing some context to children.
-            ExprKind::Field(ref subexpression, _) => {
-                self.resolve_expr(subexpression, Some(expr));
-            }
-            ExprKind::MethodCall(ref segment, ref arguments) => {
-                let mut arguments = arguments.iter();
-                self.resolve_expr(arguments.next().unwrap(), Some(expr));
-                for argument in arguments {
-                    self.resolve_expr(argument, None);
-                }
-                self.visit_path_segment(expr.span, segment);
-            }
-
-            ExprKind::Call(ref callee, ref arguments) => {
-                self.resolve_expr(callee, Some(expr));
-                for argument in arguments {
-                    self.resolve_expr(argument, None);
-                }
-            }
-            ExprKind::Type(ref type_expr, _) => {
-                self.current_type_ascription.push(type_expr.span);
-                visit::walk_expr(self, expr);
-                self.current_type_ascription.pop();
-            }
-            // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
-            // resolve the arguments within the proper scopes so that usages of them inside the
-            // closure are detected as upvars rather than normal closure arg usages.
-            ExprKind::Closure(
-                _, IsAsync::Async { .. }, _,
-                ref fn_decl, ref body, _span,
-            ) => {
-                let rib_kind = NormalRibKind;
-                self.ribs[ValueNS].push(Rib::new(rib_kind));
-                // Resolve arguments:
-                let mut bindings_list = FxHashMap::default();
-                for argument in &fn_decl.inputs {
-                    self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
-                    self.visit_ty(&argument.ty);
-                }
-                // No need to resolve return type-- the outer closure return type is
-                // FunctionRetTy::Default
-
-                // Now resolve the inner closure
-                {
-                    // No need to resolve arguments: the inner closure has none.
-                    // Resolve the return type:
-                    visit::walk_fn_ret_ty(self, &fn_decl.output);
-                    // Resolve the body
-                    self.visit_expr(body);
-                }
-                self.ribs[ValueNS].pop();
-            }
-            _ => {
-                visit::walk_expr(self, expr);
-            }
-        }
-    }
-
-    fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
-        match expr.node {
-            ExprKind::Field(_, ident) => {
-                // FIXME(#6890): Even though you can't treat a method like a
-                // field, we need to add any trait methods we find that match
-                // the field name so that we can do some nice error reporting
-                // later on in typeck.
-                let traits = self.get_traits_containing_item(ident, ValueNS);
-                self.trait_map.insert(expr.id, traits);
-            }
-            ExprKind::MethodCall(ref segment, ..) => {
-                debug!("(recording candidate traits for expr) recording traits for {}",
-                       expr.id);
-                let traits = self.get_traits_containing_item(segment.ident, ValueNS);
-                self.trait_map.insert(expr.id, traits);
-            }
-            _ => {
-                // Nothing to do.
-            }
-        }
-    }
-
-    fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
-                                  -> Vec<TraitCandidate> {
-        debug!("(getting traits containing item) looking for '{}'", ident.name);
-
-        let mut found_traits = Vec::new();
-        // Look for the current trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            let parent_scope = &self.parent_scope();
-            if self.resolve_ident_in_module(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                parent_scope,
-                false,
-                module.span,
-            ).is_ok() {
-                let def_id = module.def_id().unwrap();
-                found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
-            }
-        }
-
-        ident.span = ident.span.modern();
-        let mut search_module = self.current_module;
-        loop {
-            self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
-            search_module = unwrap_or!(
-                self.hygienic_lexical_parent(search_module, &mut ident.span), break
-            );
-        }
-
-        if let Some(prelude) = self.prelude {
-            if !search_module.no_implicit_prelude {
-                self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits);
-            }
-        }
-
-        found_traits
-    }
-
-    fn get_traits_in_module_containing_item(&mut self,
-                                            ident: Ident,
-                                            ns: Namespace,
-                                            module: Module<'a>,
-                                            found_traits: &mut Vec<TraitCandidate>) {
-        assert!(ns == TypeNS || ns == ValueNS);
-        let mut traits = module.traits.borrow_mut();
-        if traits.is_none() {
-            let mut collected_traits = Vec::new();
-            module.for_each_child(|name, ns, binding| {
-                if ns != TypeNS { return }
-                match binding.res() {
-                    Res::Def(DefKind::Trait, _) |
-                    Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)),
-                    _ => (),
-                }
-            });
-            *traits = Some(collected_traits.into_boxed_slice());
-        }
-
-        for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
-            // Traits have pseudo-modules that can be used to search for the given ident.
-            if let Some(module) = binding.module() {
-                let mut ident = ident;
-                if ident.span.glob_adjust(
-                    module.expansion,
-                    binding.span,
-                ).is_none() {
-                    continue
-                }
-                let parent_scope = &self.parent_scope();
-                if self.resolve_ident_in_module_unadjusted(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    parent_scope,
-                    false,
-                    module.span,
-                ).is_ok() {
-                    let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                    let trait_def_id = module.def_id().unwrap();
-                    found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-                }
-            } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
-                // For now, just treat all trait aliases as possible candidates, since we don't
-                // know if the ident is somewhere in the transitive bounds.
-                let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
-                let trait_def_id = binding.res().def_id();
-                found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
-            } else {
-                bug!("candidate is not trait or trait alias?")
-            }
-        }
-    }
 
-    fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>,
-                               trait_name: Ident) -> SmallVec<[NodeId; 1]> {
-        let mut import_ids = smallvec![];
-        while let NameBindingKind::Import { directive, binding, .. } = kind {
-            self.maybe_unused_trait_imports.insert(directive.id);
-            self.add_to_glob_map(&directive, trait_name);
-            import_ids.push(directive.id);
-            kind = &binding.kind;
-        };
-        import_ids
-    }
-}
-
-impl<'a> Resolver<'a> {
     fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         debug!("(recording res) recording {:?} for {}", resolution, node_id);
         if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
@@ -5190,14 +3244,74 @@ impl<'a> Resolver<'a> {
             }
         })
     }
-}
 
-fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
-    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
-}
+    /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
+    /// isn't something that can be returned because it can't be made to live that long,
+    /// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
+    /// just that an error occurred.
+    pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool)
+        -> Result<(ast::Path, Res), ()> {
+        let path = if path_str.starts_with("::") {
+            ast::Path {
+                span,
+                segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot))
+                    .chain({
+                        path_str.split("::").skip(1).map(Ident::from_str)
+                    })
+                    .map(|i| self.new_ast_path_segment(i))
+                    .collect(),
+            }
+        } else {
+            ast::Path {
+                span,
+                segments: path_str
+                    .split("::")
+                    .map(Ident::from_str)
+                    .map(|i| self.new_ast_path_segment(i))
+                    .collect(),
+            }
+        };
+        let res = self.resolve_ast_path_inner(&path, is_value).map_err(|_| ())?;
+        Ok((path, res))
+    }
 
-fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
-    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
+    /// Like `resolve_ast_path`, but takes a callback in case there was an error.
+    fn resolve_ast_path_inner(
+        &mut self,
+        path: &ast::Path,
+        is_value: bool,
+    ) -> Result<Res, (Span, ResolutionError<'a>)> {
+        let namespace = if is_value { ValueNS } else { TypeNS };
+        let span = path.span;
+        let path = Segment::from_path(&path);
+        // FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
+        let parent_scope = &self.dummy_parent_scope();
+        match self.resolve_path(&path, Some(namespace), parent_scope, true, span, CrateLint::No) {
+            PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
+                Ok(module.res().unwrap()),
+            PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
+                Ok(path_res.base_res()),
+            PathResult::NonModule(..) => {
+                Err((span, ResolutionError::FailedToResolve {
+                    label: String::from("type-relative paths are not supported in this context"),
+                    suggestion: None,
+                }))
+            }
+            PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
+            PathResult::Failed { span, label, suggestion, .. } => {
+                Err((span, ResolutionError::FailedToResolve {
+                    label,
+                    suggestion,
+                }))
+            }
+        }
+    }
+
+    fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
+        let mut seg = ast::PathSegment::from_ident(ident);
+        seg.id = self.session.next_node_id();
+        seg
+    }
 }
 
 fn names_to_string(idents: &[Ident]) -> String {