about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-08-10 13:44:09 +0000
committerbors <bors@rust-lang.org>2019-08-10 13:44:09 +0000
commitbe3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9 (patch)
treefe885a011883ee12dac655f48cea6a471b5ff281 /src
parent6f70adcb18e5dc8df0672898a8404fd05a9c32cb (diff)
parent808f98378e28d9e32c6ac76ced921bc2c1fc8114 (diff)
downloadrust-be3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9.tar.gz
rust-be3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9.zip
Auto merge of #63437 - Centril:rollup-ryx881p, r=Centril
Rollup of 4 pull requests

Successful merges:

 - #63400 (Try to break resolve into more isolated parts)
 - #63425 (Cleanup historical stability comments)
 - #63429 (.gitignore: Readd `/tmp/`)
 - #63432 (Cleanup & Simplify stuff in lowering)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs92
-rw-r--r--src/librustc_driver/lib.rs21
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs750
-rw-r--r--src/librustc_resolve/check_unused.rs201
-rw-r--r--src/librustc_resolve/diagnostics.rs907
-rw-r--r--src/librustc_resolve/late.rs2004
-rw-r--r--src/librustc_resolve/late/diagnostics.rs770
-rw-r--r--src/librustc_resolve/lib.rs2725
-rw-r--r--src/librustc_resolve/macros.rs139
-rw-r--r--src/librustc_resolve/resolve_imports.rs231
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs21
-rw-r--r--src/test/ui/hygiene/privacy-early.rs17
-rw-r--r--src/test/ui/hygiene/privacy-early.stderr21
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs2
-rw-r--r--src/test/ui/resolve/resolve-bad-visibility.rs4
-rw-r--r--src/test/ui/resolve/resolve-bad-visibility.stderr21
-rw-r--r--src/test/ui/resolve/visibility-indeterminate.rs5
-rw-r--r--src/test/ui/resolve/visibility-indeterminate.stderr19
-rw-r--r--src/test/ui/span/visibility-ty-params.stderr14
19 files changed, 4022 insertions, 3942 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 493083c680a..591ceaf28a6 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -37,7 +37,7 @@ use crate::hir::{self, ParamName};
 use crate::hir::HirVec;
 use crate::hir::map::{DefKey, DefPathData, Definitions};
 use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
-use crate::hir::def::{Res, DefKind, PartialRes, PerNS};
+use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS};
 use crate::hir::{GenericArg, ConstArg};
 use crate::hir::ptr::P;
 use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
@@ -148,13 +148,6 @@ pub struct LoweringContext<'a> {
 }
 
 pub trait Resolver {
-    /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
-    fn resolve_ast_path(
-        &mut self,
-        path: &ast::Path,
-        is_value: bool,
-    ) -> Res<NodeId>;
-
     /// Obtain resolution for a `NodeId` with a single resolution.
     fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
 
@@ -175,7 +168,7 @@ pub trait Resolver {
         span: Span,
         crate_root: Option<Symbol>,
         components: &[Symbol],
-        is_value: bool,
+        ns: Namespace,
     ) -> (ast::Path, Res<NodeId>);
 
     fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
@@ -4447,23 +4440,23 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> {
+        exprs.iter().map(|x| self.lower_expr(x)).collect()
+    }
+
     fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
         let kind = match e.node {
             ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
-            ExprKind::Array(ref exprs) => {
-                hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect())
-            }
+            ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
             ExprKind::Repeat(ref expr, ref count) => {
                 let expr = P(self.lower_expr(expr));
                 let count = self.lower_anon_const(count);
                 hir::ExprKind::Repeat(expr, count)
             }
-            ExprKind::Tup(ref elts) => {
-                hir::ExprKind::Tup(elts.iter().map(|x| self.lower_expr(x)).collect())
-            }
+            ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
             ExprKind::Call(ref f, ref args) => {
                 let f = P(self.lower_expr(f));
-                hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect())
+                hir::ExprKind::Call(f, self.lower_exprs(args))
             }
             ExprKind::MethodCall(ref seg, ref args) => {
                 let hir_seg = P(self.lower_path_segment(
@@ -4475,7 +4468,7 @@ impl<'a> LoweringContext<'a> {
                     ImplTraitContext::disallowed(),
                     None,
                 ));
-                let args = args.iter().map(|x| self.lower_expr(x)).collect();
+                let args = self.lower_exprs(args);
                 hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
             }
             ExprKind::Binary(binop, ref lhs, ref rhs) => {
@@ -5049,17 +5042,9 @@ impl<'a> LoweringContext<'a> {
                     ));
                     let arms = hir_vec![pat_arm, break_arm];
 
-                    P(self.expr(
-                        head_sp,
-                        hir::ExprKind::Match(
-                            next_expr,
-                            arms,
-                            hir::MatchSource::ForLoopDesugar
-                        ),
-                        ThinVec::new(),
-                    ))
+                    self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
                 };
-                let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr));
+                let match_stmt = self.stmt_expr(head_sp, match_expr);
 
                 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
 
@@ -5083,8 +5068,8 @@ impl<'a> LoweringContext<'a> {
                 );
 
                 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
-                let body_expr = P(self.expr_block(body_block, ThinVec::new()));
-                let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr));
+                let body_expr = self.expr_block(body_block, ThinVec::new());
+                let body_stmt = self.stmt_expr(body.span, body_expr);
 
                 let loop_block = P(self.block_all(
                     e.span,
@@ -5127,8 +5112,10 @@ impl<'a> LoweringContext<'a> {
                 ));
 
                 // This is effectively `{ let _result = ...; _result }`.
-                // The construct was introduced in #21984.
-                // FIXME(60253): Is this still necessary?
+                // The construct was introduced in #21984 and is necessary to make sure that
+                // temporaries in the `head` expression are dropped and do not leak to the
+                // surrounding scope of the `match` since the `match` is not a terminating scope.
+                //
                 // Also, add the attributes to the outer returned expr node.
                 return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
             }
@@ -5254,7 +5241,7 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> {
-        smallvec![match s.node {
+        let node = match s.node {
             StmtKind::Local(ref l) => {
                 let (l, item_ids) = self.lower_local(l);
                 let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
@@ -5291,21 +5278,14 @@ impl<'a> LoweringContext<'a> {
                     })
                     .collect();
             }
-            StmtKind::Expr(ref e) => {
-                hir::Stmt {
-                    hir_id: self.lower_node_id(s.id),
-                    node: hir::StmtKind::Expr(P(self.lower_expr(e))),
-                    span: s.span,
-                }
-            },
-            StmtKind::Semi(ref e) => {
-                hir::Stmt {
-                    hir_id: self.lower_node_id(s.id),
-                    node: hir::StmtKind::Semi(P(self.lower_expr(e))),
-                    span: s.span,
-                }
-            },
+            StmtKind::Expr(ref e) => hir::StmtKind::Expr(P(self.lower_expr(e))),
+            StmtKind::Semi(ref e) => hir::StmtKind::Semi(P(self.lower_expr(e))),
             StmtKind::Mac(..) => panic!("Shouldn't exist here"),
+        };
+        smallvec![hir::Stmt {
+            hir_id: self.lower_node_id(s.id),
+            node,
+            span: s.span,
         }]
     }
 
@@ -5567,6 +5547,10 @@ impl<'a> LoweringContext<'a> {
         hir::Stmt { span, node, hir_id: self.next_id() }
     }
 
+    fn stmt_expr(&mut self, span: Span, expr: hir::Expr) -> hir::Stmt {
+        self.stmt(span, hir::StmtKind::Expr(P(expr)))
+    }
+
     fn stmt_let_pat(
         &mut self,
         attrs: ThinVec<Attribute>,
@@ -5717,8 +5701,8 @@ impl<'a> LoweringContext<'a> {
         params: Option<P<hir::GenericArgs>>,
         is_value: bool,
     ) -> hir::Path {
-        let (path, res) = self.resolver
-            .resolve_str_path(span, self.crate_root, components, is_value);
+        let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
+        let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
 
         let mut segments: Vec<_> = path.segments.iter().map(|segment| {
             let res = self.expect_full_res(segment.id);
@@ -6060,23 +6044,23 @@ impl<'a> LoweringContext<'a> {
         };
 
         let match_stmt = {
-            let match_expr = P(self.expr_match(
+            let match_expr = self.expr_match(
                 span,
                 poll_expr,
                 hir_vec![ready_arm, pending_arm],
                 hir::MatchSource::AwaitDesugar,
-            ));
-            self.stmt(span, hir::StmtKind::Expr(match_expr))
+            );
+            self.stmt_expr(span, match_expr)
         };
 
         let yield_stmt = {
             let unit = self.expr_unit(span);
-            let yield_expr = P(self.expr(
+            let yield_expr = self.expr(
                 span,
                 hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
                 ThinVec::new(),
-            ));
-            self.stmt(span, hir::StmtKind::Expr(yield_expr))
+            );
+            self.stmt_expr(span, yield_expr)
         };
 
         let loop_block = P(self.block_all(
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 77b7ef96d3f..e9d85a53d1e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -957,14 +957,11 @@ fn print_flag_list<T>(cmdline_opt: &str,
 /// otherwise returns `None`.
 ///
 /// The compiler's handling of options is a little complicated as it ties into
-/// our stability story, and it's even *more* complicated by historical
-/// accidents. The current intention of each compiler option is to have one of
-/// three modes:
+/// our stability story. The current intention of each compiler option is to
+/// have one of two modes:
 ///
 /// 1. An option is stable and can be used everywhere.
-/// 2. An option is unstable, but was historically allowed on the stable
-///    channel.
-/// 3. An option is unstable, and can only be used on nightly.
+/// 2. An option is unstable, and can only be used on nightly.
 ///
 /// Like unstable library and language features, however, unstable options have
 /// always required a form of "opt in" to indicate that you're using them. This
@@ -1007,19 +1004,13 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     //   this option that was passed.
     // * If we're a nightly compiler, then unstable options are now unlocked, so
     //   we're good to go.
-    // * Otherwise, if we're a truly unstable option then we generate an error
+    // * Otherwise, if we're an unstable option then we generate an error
     //   (unstable option being used on stable)
-    // * If we're a historically stable-but-should-be-unstable option then we
-    //   emit a warning that we're going to turn this into an error soon.
     nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
 
     if matches.opt_present("h") || matches.opt_present("help") {
-        // Only show unstable options in --help if we *really* accept unstable
-        // options, which catches the case where we got `-Z unstable-options` on
-        // the stable channel of Rust which was accidentally allowed
-        // historically.
-        usage(matches.opt_present("verbose"),
-              nightly_options::is_unstable_enabled(&matches));
+        // Only show unstable options in --help if we accept unstable options.
+        usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches));
         return None;
     }
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 9d01f330029..6e5750e752e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -3,13 +3,13 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
-use crate::macros::{InvocationData, LegacyScope};
+use crate::macros::{InvocationData, LegacyBinding, LegacyScope};
 use crate::resolve_imports::ImportDirective;
 use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
 use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
 use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
 use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
-use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy};
+use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
 
 use rustc::bug;
 use rustc::hir::def::{self, *};
@@ -29,11 +29,11 @@ use syntax::attr;
 
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
 use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant};
-use syntax::ext::base::SyntaxExtension;
+use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::hygiene::ExpnId;
 use syntax::feature_gate::is_builtin_attr;
 use syntax::parse::token::{self, Token};
-use syntax::span_err;
+use syntax::{span_err, struct_span_err};
 use syntax::symbol::{kw, sym};
 use syntax::visit::{self, Visitor};
 
@@ -93,6 +93,195 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
+        if def_id.krate == LOCAL_CRATE {
+            return self.module_map[&def_id]
+        }
+
+        let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only();
+        if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
+            return module;
+        }
+
+        let (name, parent) = if def_id.index == CRATE_DEF_INDEX {
+            (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None)
+        } else {
+            let def_key = self.cstore.def_key(def_id);
+            (def_key.disambiguated_data.data.get_opt_name().unwrap(),
+             Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })))
+        };
+
+        let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol());
+        let module = self.arenas.alloc_module(ModuleData::new(
+            parent, kind, def_id, ExpnId::root(), DUMMY_SP
+        ));
+        self.extern_module_map.insert((def_id, macros_only), module);
+        module
+    }
+
+    pub fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
+        let def_id = match self.macro_defs.get(&expn_id) {
+            Some(def_id) => *def_id,
+            None => return self.graph_root,
+        };
+        if let Some(id) = self.definitions.as_local_node_id(def_id) {
+            self.local_macro_def_scopes[&id]
+        } else if self.is_builtin_macro(Some(def_id)) {
+            self.injected_crate.unwrap_or(self.graph_root)
+        } else {
+            let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
+            self.get_module(module_def_id)
+        }
+    }
+
+    crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
+        match res {
+            Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
+            Res::NonMacroAttr(attr_kind) =>
+                Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)),
+            _ => None,
+        }
+    }
+
+    crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>> {
+        if let Some(ext) = self.macro_map.get(&def_id) {
+            return Some(ext.clone());
+        }
+
+        let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) {
+            LoadedMacro::MacroDef(macro_def) => macro_def,
+            LoadedMacro::ProcMacro(ext) => return Some(ext),
+        };
+
+        let ext = self.compile_macro(&macro_def, self.cstore.crate_edition_untracked(def_id.krate));
+        self.macro_map.insert(def_id, ext.clone());
+        Some(ext)
+    }
+
+    /// Ensures that the reduced graph rooted at the given external module
+    /// is built, building it if it is not.
+    pub fn populate_module_if_necessary(&mut self, module: Module<'a>) {
+        if module.populated.get() { return }
+        let def_id = module.def_id().unwrap();
+        for child in self.cstore.item_children_untracked(def_id, self.session) {
+            let child = child.map_id(|_| panic!("unexpected id"));
+            BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self }
+                .build_reduced_graph_for_external_crate_res(module, child);
+        }
+        module.populated.set(true)
+    }
+}
+
+pub struct BuildReducedGraphVisitor<'a, 'b> {
+    pub r: &'b mut Resolver<'a>,
+    pub parent_scope: ParentScope<'a>,
+}
+
+impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
+    fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
+        let parent_scope = &self.parent_scope;
+        match vis.node {
+            ast::VisibilityKind::Public => ty::Visibility::Public,
+            ast::VisibilityKind::Crate(..) => {
+                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+            }
+            ast::VisibilityKind::Inherited => {
+                ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
+            }
+            ast::VisibilityKind::Restricted { ref path, id, .. } => {
+                // For visibilities we are not ready to provide correct implementation of "uniform
+                // paths" right now, so on 2018 edition we only allow module-relative paths for now.
+                // On 2015 edition visibilities are resolved as crate-relative by default,
+                // so we are prepending a root segment if necessary.
+                let ident = path.segments.get(0).expect("empty path in visibility").ident;
+                let crate_root = if ident.is_path_segment_keyword() {
+                    None
+                } else if ident.span.rust_2018() {
+                    let msg = "relative paths are not supported in visibilities on 2018 edition";
+                    self.r.session.struct_span_err(ident.span, msg)
+                        .span_suggestion(
+                            path.span,
+                            "try",
+                            format!("crate::{}", path),
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                    return ty::Visibility::Public;
+                } else {
+                    let ctxt = ident.span.ctxt();
+                    Some(Segment::from_ident(Ident::new(
+                        kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
+                    )))
+                };
+
+                let segments = crate_root.into_iter()
+                    .chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
+                let expected_found_error = |this: &Self, res: Res| {
+                    let path_str = Segment::names_to_string(&segments);
+                    struct_span_err!(this.r.session, path.span, E0577,
+                                     "expected module, found {} `{}`", res.descr(), path_str)
+                        .span_label(path.span, "not a module").emit();
+                };
+                match self.r.resolve_path(
+                    &segments,
+                    Some(TypeNS),
+                    parent_scope,
+                    true,
+                    path.span,
+                    CrateLint::SimplePath(id),
+                ) {
+                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
+                        let res = module.res().expect("visibility resolved to unnamed block");
+                        self.r.record_partial_res(id, PartialRes::new(res));
+                        if module.is_normal() {
+                            if res == Res::Err {
+                                ty::Visibility::Public
+                            } else {
+                                let vis = ty::Visibility::Restricted(res.def_id());
+                                if self.r.is_accessible_from(vis, parent_scope.module) {
+                                    vis
+                                } else {
+                                    let msg =
+                                        "visibilities can only be restricted to ancestor modules";
+                                    self.r.session.span_err(path.span, msg);
+                                    ty::Visibility::Public
+                                }
+                            }
+                        } else {
+                            expected_found_error(self, res);
+                            ty::Visibility::Public
+                        }
+                    }
+                    PathResult::Module(..) => {
+                        self.r.session.span_err(path.span, "visibility must resolve to a module");
+                        ty::Visibility::Public
+                    }
+                    PathResult::NonModule(partial_res) => {
+                        expected_found_error(self, partial_res.base_res());
+                        ty::Visibility::Public
+                    }
+                    PathResult::Failed { span, label, suggestion, .. } => {
+                        self.r.report_error(
+                            span, ResolutionError::FailedToResolve { label, suggestion }
+                        );
+                        ty::Visibility::Public
+                    }
+                    PathResult::Indeterminate => {
+                        span_err!(self.r.session, path.span, E0578,
+                                  "cannot determine resolution for the visibility");
+                        ty::Visibility::Public
+                    }
+                }
+            }
+        }
+    }
+
+    fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Name>) {
+        if !field_names.is_empty() {
+            self.r.field_names.insert(def_id, field_names);
+        }
+    }
+
     fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
         // If any statements are items, we need to create an anonymous module
         block.stmts.iter().any(|statement| match statement.node {
@@ -101,9 +290,51 @@ impl<'a> Resolver<'a> {
         })
     }
 
-    fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Name>) {
-        if !field_names.is_empty() {
-            self.field_names.insert(def_id, field_names);
+    // Add an import directive to the current module.
+    fn add_import_directive(
+        &mut self,
+        module_path: Vec<Segment>,
+        subclass: ImportDirectiveSubclass<'a>,
+        span: Span,
+        id: NodeId,
+        item: &ast::Item,
+        root_span: Span,
+        root_id: NodeId,
+        vis: ty::Visibility,
+    ) {
+        let parent_scope = &self.parent_scope;
+        let current_module = parent_scope.module;
+        let directive = self.r.arenas.alloc_import_directive(ImportDirective {
+            parent_scope: parent_scope.clone(),
+            module_path,
+            imported_module: Cell::new(None),
+            subclass,
+            span,
+            id,
+            use_span: item.span,
+            use_span_with_attributes: item.span_with_attributes(),
+            has_attributes: !item.attrs.is_empty(),
+            root_span,
+            root_id,
+            vis: Cell::new(vis),
+            used: Cell::new(false),
+        });
+
+        debug!("add_import_directive({:?})", directive);
+
+        self.r.indeterminate_imports.push(directive);
+        match directive.subclass {
+            SingleImport { target, type_ns_only, .. } => {
+                self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+                    let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
+                    resolution.add_single_import(directive);
+                });
+            }
+            // We don't add prelude imports to the globs since they only affect lexical scopes,
+            // which are not relevant to import resolution.
+            GlobImport { is_prelude: true, .. } => {}
+            GlobImport { .. } => current_module.globs.borrow_mut().push(directive),
+            _ => unreachable!(),
         }
     }
 
@@ -115,7 +346,6 @@ impl<'a> Resolver<'a> {
         parent_prefix: &[Segment],
         nested: bool,
         // The whole `use` item
-        parent_scope: ParentScope<'a>,
         item: &Item,
         vis: ty::Visibility,
         root_span: Span,
@@ -163,8 +393,7 @@ impl<'a> Resolver<'a> {
                         type_ns_only = true;
 
                         if empty_for_self(&module_path) {
-                            resolve_error(
-                                self,
+                            self.r.report_error(
                                 use_tree.span,
                                 ResolutionError::
                                 SelfImportOnlyInImportListWithNonEmptyPrefix
@@ -181,14 +410,14 @@ impl<'a> Resolver<'a> {
                 } else {
                     // Disallow `self`
                     if source.ident.name == kw::SelfLower {
-                        resolve_error(self,
-                                      use_tree.span,
-                                      ResolutionError::SelfImportsOnlyAllowedWithin);
+                        self.r.report_error(
+                            use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin
+                        );
                     }
 
                     // Disallow `use $crate;`
                     if source.ident.name == kw::DollarCrate && module_path.is_empty() {
-                        let crate_root = self.resolve_crate_root(source.ident);
+                        let crate_root = self.r.resolve_crate_root(source.ident);
                         let crate_name = match crate_root.kind {
                             ModuleKind::Def(.., name) => name,
                             ModuleKind::Block(..) => unreachable!(),
@@ -203,7 +432,7 @@ impl<'a> Resolver<'a> {
                                     name: kw::PathRoot,
                                     span: source.ident.span,
                                 },
-                                id: Some(self.session.next_node_id()),
+                                id: Some(self.r.session.next_node_id()),
                             });
                             source.ident.name = crate_name;
                         }
@@ -211,7 +440,7 @@ impl<'a> Resolver<'a> {
                             ident.name = crate_name;
                         }
 
-                        self.session.struct_span_warn(item.span, "`$crate` may not be imported")
+                        self.r.session.struct_span_warn(item.span, "`$crate` may not be imported")
                             .note("`use $crate;` was erroneously allowed and \
                                    will become a hard error in a future release")
                             .emit();
@@ -219,7 +448,7 @@ impl<'a> Resolver<'a> {
                 }
 
                 if ident.name == kw::Crate {
-                    self.session.span_err(ident.span,
+                    self.r.session.span_err(ident.span,
                         "crate root imports need to be explicitly named: \
                          `use crate as name;`");
                 }
@@ -249,7 +478,6 @@ impl<'a> Resolver<'a> {
                     root_span,
                     item.id,
                     vis,
-                    parent_scope,
                 );
             }
             ast::UseTreeKind::Glob => {
@@ -266,7 +494,6 @@ impl<'a> Resolver<'a> {
                     root_span,
                     item.id,
                     vis,
-                    parent_scope,
                 );
             }
             ast::UseTreeKind::Nested(ref items) => {
@@ -281,7 +508,7 @@ impl<'a> Resolver<'a> {
                     None
                 }).collect::<Vec<_>>();
                 if self_spans.len() > 1 {
-                    let mut e = resolve_struct_error(self,
+                    let mut e = self.r.into_struct_error(
                         self_spans[0],
                         ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
 
@@ -297,7 +524,7 @@ impl<'a> Resolver<'a> {
                         // This particular use tree
                         tree, id, &prefix, true,
                         // The whole `use` item
-                        parent_scope.clone(), item, vis, root_span,
+                        item, vis, root_span,
                     );
                 }
 
@@ -321,7 +548,7 @@ impl<'a> Resolver<'a> {
                         // This particular use tree
                         &tree, id, &prefix, true,
                         // The whole `use` item
-                        parent_scope, item, ty::Visibility::Invisible, root_span,
+                        item, ty::Visibility::Invisible, root_span,
                     );
                 }
             }
@@ -329,7 +556,8 @@ impl<'a> Resolver<'a> {
     }
 
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) {
+    fn build_reduced_graph_for_item(&mut self, item: &Item) {
+        let parent_scope = &self.parent_scope;
         let parent = parent_scope.module;
         let expansion = parent_scope.expansion;
         let ident = item.ident.gensym_if_underscore();
@@ -342,13 +570,13 @@ impl<'a> Resolver<'a> {
                     // This particular use tree
                     use_tree, item.id, &[], false,
                     // The whole `use` item
-                    parent_scope, item, vis, use_tree.span,
+                    item, vis, use_tree.span,
                 );
             }
 
             ItemKind::ExternCrate(orig_name) => {
                 let module = if orig_name.is_none() && ident.name == kw::SelfLower {
-                    self.session
+                    self.r.session
                         .struct_span_err(item.span, "`extern crate self;` requires renaming")
                         .span_suggestion(
                             item.span,
@@ -359,26 +587,28 @@ impl<'a> Resolver<'a> {
                         .emit();
                     return;
                 } else if orig_name == Some(kw::SelfLower) {
-                    self.graph_root
+                    self.r.graph_root
                 } else {
-                    let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions);
-                    self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+                    let crate_id = self.r.crate_loader.process_extern_crate(
+                        item, &self.r.definitions
+                    );
+                    self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
 
-                self.populate_module_if_necessary(module);
-                if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() {
+                self.r.populate_module_if_necessary(module);
+                if let Some(name) = self.r.session.parse_sess.injected_crate_name.try_get() {
                     if name.as_str() == ident.name.as_str() {
-                        self.injected_crate = Some(module);
+                        self.r.injected_crate = Some(module);
                     }
                 }
 
-                let used = self.process_legacy_macro_imports(item, module, &parent_scope);
+                let used = self.process_legacy_macro_imports(item, module);
                 let binding =
-                    (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
-                let directive = self.arenas.alloc_import_directive(ImportDirective {
+                    (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+                let directive = self.r.arenas.alloc_import_directive(ImportDirective {
                     root_id: item.id,
                     id: item.id,
-                    parent_scope,
+                    parent_scope: self.parent_scope.clone(),
                     imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
                     subclass: ImportDirectiveSubclass::ExternCrate {
                         source: orig_name,
@@ -393,18 +623,18 @@ impl<'a> Resolver<'a> {
                     vis: Cell::new(vis),
                     used: Cell::new(used),
                 });
-                self.potentially_unused_imports.push(directive);
-                let imported_binding = self.import(binding, directive);
-                if ptr::eq(self.current_module, self.graph_root) {
-                    if let Some(entry) = self.extern_prelude.get(&ident.modern()) {
+                self.r.potentially_unused_imports.push(directive);
+                let imported_binding = self.r.import(binding, directive);
+                if ptr::eq(parent, self.r.graph_root) {
+                    if let Some(entry) = self.r.extern_prelude.get(&ident.modern()) {
                         if expansion != ExpnId::root() && orig_name.is_some() &&
                            entry.extern_crate_item.is_none() {
-                            self.session.span_err(item.span, "macro-expanded `extern crate` items \
-                                                              cannot shadow names passed with \
-                                                              `--extern`");
+                            let msg = "macro-expanded `extern crate` items cannot \
+                                       shadow names passed with `--extern`";
+                            self.r.session.span_err(item.span, msg);
                         }
                     }
-                    let entry = self.extern_prelude.entry(ident.modern())
+                    let entry = self.r.extern_prelude.entry(ident.modern())
                                                    .or_insert(ExternPreludeEntry {
                         extern_crate_item: None,
                         introduced_by_item: true,
@@ -414,7 +644,7 @@ impl<'a> Resolver<'a> {
                         entry.introduced_by_item = true;
                     }
                 }
-                self.define(parent, ident, TypeNS, imported_binding);
+                self.r.define(parent, ident, TypeNS, imported_binding);
             }
 
             ItemKind::GlobalAsm(..) => {}
@@ -422,19 +652,19 @@ impl<'a> Resolver<'a> {
             ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
 
             ItemKind::Mod(..) => {
-                let def_id = self.definitions.local_def_id(item.id);
+                let def_id = self.r.definitions.local_def_id(item.id);
                 let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
-                let module = self.arenas.alloc_module(ModuleData {
+                let module = self.r.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
                         attr::contains_name(&item.attrs, sym::no_implicit_prelude)
                     },
                     ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
                 });
-                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-                self.module_map.insert(def_id, module);
+                self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
+                self.r.module_map.insert(def_id, module);
 
                 // Descend into the module.
-                self.current_module = module;
+                self.parent_scope.module = module;
             }
 
             // Handled in `rustc_metadata::{native_libs,link_args}`
@@ -442,45 +672,45 @@ impl<'a> Resolver<'a> {
 
             // These items live in the value namespace.
             ItemKind::Static(..) => {
-                let res = Res::Def(DefKind::Static, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
-                let res = Res::Def(DefKind::Const, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Fn(..) => {
-                let res = Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
 
                 // Functions introducing procedural macros reserve a slot
                 // in the macro namespace as well (see #52225).
-                self.define_macro(item, expansion, &mut LegacyScope::Empty);
+                self.define_macro(item);
             }
 
             // These items live in the type namespace.
             ItemKind::TyAlias(..) => {
-                let res = Res::Def(DefKind::TyAlias, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::TyAlias, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             ItemKind::OpaqueTy(_, _) => {
-                let res = Res::Def(DefKind::OpaqueTy, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::OpaqueTy, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             ItemKind::Enum(ref enum_definition, _) => {
                 let module_kind = ModuleKind::Def(
                     DefKind::Enum,
-                    self.definitions.local_def_id(item.id),
+                    self.r.definitions.local_def_id(item.id),
                     ident.name,
                 );
-                let module = self.new_module(parent,
+                let module = self.r.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
                                              expansion,
                                              item.span);
-                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
+                self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
                 for variant in &(*enum_definition).variants {
                     self.build_reduced_graph_for_variant(variant, module, vis, expansion);
@@ -488,16 +718,16 @@ impl<'a> Resolver<'a> {
             }
 
             ItemKind::TraitAlias(..) => {
-                let res = Res::Def(DefKind::TraitAlias, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::TraitAlias, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref struct_def, _) => {
                 // Define a name in the type namespace.
-                let def_id = self.definitions.local_def_id(item.id);
+                let def_id = self.r.definitions.local_def_id(item.id);
                 let res = Res::Def(DefKind::Struct, def_id);
-                self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
                 let mut ctor_vis = vis;
 
@@ -512,12 +742,12 @@ impl<'a> Resolver<'a> {
                 // Record field names for error reporting.
                 let field_names = struct_def.fields().iter().filter_map(|field| {
                     let field_vis = self.resolve_visibility(&field.vis);
-                    if ctor_vis.is_at_least(field_vis, &*self) {
+                    if ctor_vis.is_at_least(field_vis, &*self.r) {
                         ctor_vis = field_vis;
                     }
                     field.ident.map(|ident| ident.name)
                 }).collect();
-                let item_def_id = self.definitions.local_def_id(item.id);
+                let item_def_id = self.r.definitions.local_def_id(item.id);
                 self.insert_field_names(item_def_id, field_names);
 
                 // If this is a tuple or unit struct, define a name
@@ -525,40 +755,44 @@ impl<'a> Resolver<'a> {
                 if let Some(ctor_node_id) = struct_def.ctor_id() {
                     let ctor_res = Res::Def(
                         DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
-                        self.definitions.local_def_id(ctor_node_id),
+                        self.r.definitions.local_def_id(ctor_node_id),
                     );
-                    self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
-                    self.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
+                    self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
+                    self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
                 }
             }
 
             ItemKind::Union(ref vdata, _) => {
-                let res = Res::Def(DefKind::Union, self.definitions.local_def_id(item.id));
-                self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
+                let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id));
+                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
                 // Record field names for error reporting.
                 let field_names = vdata.fields().iter().filter_map(|field| {
                     self.resolve_visibility(&field.vis);
                     field.ident.map(|ident| ident.name)
                 }).collect();
-                let item_def_id = self.definitions.local_def_id(item.id);
+                let item_def_id = self.r.definitions.local_def_id(item.id);
                 self.insert_field_names(item_def_id, field_names);
             }
 
-            ItemKind::Impl(..) => {}
+            ItemKind::Impl(.., ref impl_items) => {
+                for impl_item in impl_items {
+                    self.resolve_visibility(&impl_item.vis);
+                }
+            }
 
             ItemKind::Trait(..) => {
-                let def_id = self.definitions.local_def_id(item.id);
+                let def_id = self.r.definitions.local_def_id(item.id);
 
                 // Add all the items within to a new module.
                 let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
-                let module = self.new_module(parent,
+                let module = self.r.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
                                              expansion,
                                              item.span);
-                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-                self.current_module = module;
+                self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
+                self.parent_scope.module = module;
             }
 
             ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
@@ -575,9 +809,9 @@ impl<'a> Resolver<'a> {
         let ident = variant.node.ident;
 
         // Define a name in the type namespace.
-        let def_id = self.definitions.local_def_id(variant.node.id);
+        let def_id = self.r.definitions.local_def_id(variant.node.id);
         let res = Res::Def(DefKind::Variant, def_id);
-        self.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
+        self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the
         // crate.
@@ -593,41 +827,43 @@ impl<'a> Resolver<'a> {
         // It's ok to use the variant's id as a ctor id since an
         // error will be reported on any use of such resolution anyway.
         let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id);
-        let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
+        let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id);
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
         let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
-        self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
+        self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
     }
 
     /// Constructs the reduced graph for one foreign item.
-    fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expn_id: ExpnId) {
+    fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
         let (res, ns) = match item.node {
             ForeignItemKind::Fn(..) => {
-                (Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)), ValueNS)
+                (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
             ForeignItemKind::Static(..) => {
-                (Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)), ValueNS)
+                (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
             ForeignItemKind::Ty => {
-                (Res::Def(DefKind::ForeignTy, self.definitions.local_def_id(item.id)), TypeNS)
+                (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS)
             }
             ForeignItemKind::Macro(_) => unreachable!(),
         };
-        let parent = self.current_module;
+        let parent = self.parent_scope.module;
+        let expansion = self.parent_scope.expansion;
         let vis = self.resolve_visibility(&item.vis);
-        self.define(parent, item.ident, ns, (res, vis, item.span, expn_id));
+        self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
     }
 
-    fn build_reduced_graph_for_block(&mut self, block: &Block, expn_id: ExpnId) {
-        let parent = self.current_module;
+    fn build_reduced_graph_for_block(&mut self, block: &Block) {
+        let parent = self.parent_scope.module;
+        let expansion = self.parent_scope.expansion;
         if self.block_needs_anonymous_module(block) {
-            let module = self.new_module(parent,
+            let module = self.r.new_module(parent,
                                          ModuleKind::Block(block.id),
                                          parent.normal_ancestor_id,
-                                         expn_id,
+                                         expansion,
                                          block.span);
-            self.block_map.insert(block.id, module);
-            self.current_module = module; // Descend into the block.
+            self.r.block_map.insert(block.id, module);
+            self.parent_scope.module = module; // Descend into the block.
         }
     }
 
@@ -646,12 +882,12 @@ impl<'a> Resolver<'a> {
         match res {
             Res::Def(kind @ DefKind::Mod, def_id)
             | Res::Def(kind @ DefKind::Enum, def_id) => {
-                let module = self.new_module(parent,
+                let module = self.r.new_module(parent,
                                              ModuleKind::Def(kind, def_id, ident.name),
                                              def_id,
                                              expansion,
                                              span);
-                self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
             }
             Res::Def(DefKind::Variant, _)
             | Res::Def(DefKind::TyAlias, _)
@@ -660,169 +896,91 @@ impl<'a> Resolver<'a> {
             | Res::Def(DefKind::TraitAlias, _)
             | Res::PrimTy(..)
             | Res::ToolMod => {
-                self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
             }
             Res::Def(DefKind::Fn, _)
             | Res::Def(DefKind::Static, _)
             | Res::Def(DefKind::Const, _)
             | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => {
-                self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
             }
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => {
-                self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
 
                 if let Some(struct_def_id) =
-                        self.cstore.def_key(def_id).parent
+                        self.r.cstore.def_key(def_id).parent
                             .map(|index| DefId { krate: def_id.krate, index: index }) {
-                    self.struct_constructors.insert(struct_def_id, (res, vis));
+                    self.r.struct_constructors.insert(struct_def_id, (res, vis));
                 }
             }
             Res::Def(DefKind::Trait, def_id) => {
                 let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
-                let module = self.new_module(parent,
+                let module = self.r.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
                                              expansion,
                                              span);
-                self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
 
-                for child in self.cstore.item_children_untracked(def_id, self.session) {
+                for child in self.r.cstore.item_children_untracked(def_id, self.r.session) {
                     let res = child.res.map_id(|_| panic!("unexpected id"));
                     let ns = if let Res::Def(DefKind::AssocTy, _) = res {
                         TypeNS
                     } else { ValueNS };
-                    self.define(module, child.ident, ns,
+                    self.r.define(module, child.ident, ns,
                                 (res, ty::Visibility::Public, DUMMY_SP, expansion));
 
-                    if self.cstore.associated_item_cloned_untracked(child.res.def_id())
+                    if self.r.cstore.associated_item_cloned_untracked(child.res.def_id())
                            .method_has_self_argument {
-                        self.has_self.insert(res.def_id());
+                        self.r.has_self.insert(res.def_id());
                     }
                 }
                 module.populated.set(true);
             }
             Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => {
-                self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
 
                 // Record field names for error reporting.
-                let field_names = self.cstore.struct_field_names_untracked(def_id);
+                let field_names = self.r.cstore.struct_field_names_untracked(def_id);
                 self.insert_field_names(def_id, field_names);
             }
             Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
-                self.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion));
+                self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion));
             }
             _ => bug!("unexpected resolution: {:?}", res)
         }
     }
 
-    pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
-        if def_id.krate == LOCAL_CRATE {
-            return self.module_map[&def_id]
-        }
-
-        let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only();
-        if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
-            return module;
-        }
-
-        let (name, parent) = if def_id.index == CRATE_DEF_INDEX {
-            (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None)
-        } else {
-            let def_key = self.cstore.def_key(def_id);
-            (def_key.disambiguated_data.data.get_opt_name().unwrap(),
-             Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })))
-        };
-
-        let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol());
-        let module = self.arenas.alloc_module(ModuleData::new(
-            parent, kind, def_id, ExpnId::root(), DUMMY_SP
-        ));
-        self.extern_module_map.insert((def_id, macros_only), module);
-        module
-    }
-
-    pub fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
-        let def_id = match self.macro_defs.get(&expn_id) {
-            Some(def_id) => *def_id,
-            None => return self.graph_root,
-        };
-        if let Some(id) = self.definitions.as_local_node_id(def_id) {
-            self.local_macro_def_scopes[&id]
-        } else if self.is_builtin_macro(Some(def_id)) {
-            self.injected_crate.unwrap_or(self.graph_root)
-        } else {
-            let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
-            self.get_module(module_def_id)
-        }
-    }
-
-    crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
-        match res {
-            Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
-            Res::NonMacroAttr(attr_kind) =>
-                Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)),
-            _ => None,
-        }
-    }
-
-    crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>> {
-        if let Some(ext) = self.macro_map.get(&def_id) {
-            return Some(ext.clone());
-        }
-
-        let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) {
-            LoadedMacro::MacroDef(macro_def) => macro_def,
-            LoadedMacro::ProcMacro(ext) => return Some(ext),
-        };
-
-        let ext = self.compile_macro(&macro_def, self.cstore.crate_edition_untracked(def_id.krate));
-        self.macro_map.insert(def_id, ext.clone());
-        Some(ext)
-    }
-
-    /// Ensures that the reduced graph rooted at the given external module
-    /// is built, building it if it is not.
-    pub fn populate_module_if_necessary(&mut self, module: Module<'a>) {
-        if module.populated.get() { return }
-        let def_id = module.def_id().unwrap();
-        for child in self.cstore.item_children_untracked(def_id, self.session) {
-            let child = child.map_id(|_| panic!("unexpected id"));
-            self.build_reduced_graph_for_external_crate_res(module, child);
-        }
-        module.populated.set(true)
-    }
-
     fn legacy_import_macro(&mut self,
                            name: Name,
                            binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
-        if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
+        if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
             let msg = format!("`{}` is already in scope", name);
             let note =
                 "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
-            self.session.struct_span_err(span, &msg).note(note).emit();
+            self.r.session.struct_span_err(span, &msg).note(note).emit();
         }
     }
 
     /// Returns `true` if we should consider the underlying `extern crate` to be used.
-    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>,
-                                    parent_scope: &ParentScope<'a>) -> bool {
+    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> bool {
         let mut import_all = None;
         let mut single_imports = Vec::new();
         for attr in &item.attrs {
             if attr.check_name(sym::macro_use) {
-                if self.current_module.parent.is_some() {
-                    span_err!(self.session, item.span, E0468,
+                if self.parent_scope.module.parent.is_some() {
+                    span_err!(self.r.session, item.span, E0468,
                         "an `extern crate` loading macros must be at the crate root");
                 }
                 if let ItemKind::ExternCrate(Some(orig_name)) = item.node {
                     if orig_name == kw::SelfLower {
-                        self.session.span_err(attr.span,
+                        self.r.session.span_err(attr.span,
                             "`macro_use` is not supported on `extern crate self`");
                     }
                 }
-                let ill_formed = |span| span_err!(self.session, span, E0466, "bad macro import");
+                let ill_formed = |span| span_err!(self.r.session, span, E0466, "bad macro import");
                 match attr.meta() {
                     Some(meta) => match meta.node {
                         MetaItemKind::Word => {
@@ -842,11 +1000,11 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        let arenas = self.arenas;
-        let macro_use_directive = |span| arenas.alloc_import_directive(ImportDirective {
+        let macro_use_directive =
+                |this: &Self, span| this.r.arenas.alloc_import_directive(ImportDirective {
             root_id: item.id,
             id: item.id,
-            parent_scope: parent_scope.clone(),
+            parent_scope: this.parent_scope.clone(),
             imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
             subclass: ImportDirectiveSubclass::MacroUse,
             use_span_with_attributes: item.span_with_attributes(),
@@ -859,32 +1017,32 @@ impl<'a> Resolver<'a> {
             used: Cell::new(false),
         });
 
-        let allow_shadowing = parent_scope.expansion == ExpnId::root();
+        let allow_shadowing = self.parent_scope.expansion == ExpnId::root();
         if let Some(span) = import_all {
-            let directive = macro_use_directive(span);
-            self.potentially_unused_imports.push(directive);
+            let directive = macro_use_directive(self, span);
+            self.r.potentially_unused_imports.push(directive);
             module.for_each_child(|ident, ns, binding| if ns == MacroNS {
-                let imported_binding = self.import(binding, directive);
+                let imported_binding = self.r.import(binding, directive);
                 self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
             });
         } else {
             for ident in single_imports.iter().cloned() {
-                let result = self.resolve_ident_in_module(
+                let result = self.r.resolve_ident_in_module(
                     ModuleOrUniformRoot::Module(module),
                     ident,
                     MacroNS,
-                    None,
+                    &self.parent_scope,
                     false,
                     ident.span,
                 );
                 if let Ok(binding) = result {
-                    let directive = macro_use_directive(ident.span);
-                    self.potentially_unused_imports.push(directive);
-                    let imported_binding = self.import(binding, directive);
+                    let directive = macro_use_directive(self, ident.span);
+                    self.r.potentially_unused_imports.push(directive);
+                    let imported_binding = self.r.import(binding, directive);
                     self.legacy_import_macro(ident.name, imported_binding,
                                              ident.span, allow_shadowing);
                 } else {
-                    span_err!(self.session, ident.span, E0469, "imported macro not found");
+                    span_err!(self.r.session, ident.span, E0469, "imported macro not found");
                 }
             }
         }
@@ -896,7 +1054,7 @@ impl<'a> Resolver<'a> {
         for attr in attrs {
             if attr.check_name(sym::macro_escape) {
                 let msg = "macro_escape is a deprecated synonym for macro_use";
-                let mut err = self.session.struct_span_warn(attr.span, msg);
+                let mut err = self.r.session.struct_span_warn(attr.span, msg);
                 if let ast::AttrStyle::Inner = attr.style {
                     err.help("consider an outer attribute, `#[macro_use]` mod ...").emit();
                 } else {
@@ -907,42 +1065,106 @@ impl<'a> Resolver<'a> {
             }
 
             if !attr.is_word() {
-                self.session.span_err(attr.span, "arguments to macro_use are not allowed here");
+                self.r.session.span_err(attr.span, "arguments to macro_use are not allowed here");
             }
             return true;
         }
 
         false
     }
-}
-
-pub struct BuildReducedGraphVisitor<'a, 'b> {
-    pub resolver: &'a mut Resolver<'b>,
-    pub current_legacy_scope: LegacyScope<'b>,
-    pub expansion: ExpnId,
-}
 
-impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
-    fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
+    fn visit_invoc(&mut self, id: ast::NodeId) -> &'a InvocationData<'a> {
         let invoc_id = id.placeholder_to_expn_id();
 
-        self.resolver.current_module.unresolved_invocations.borrow_mut().insert(invoc_id);
+        self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
 
-        let invocation_data = self.resolver.arenas.alloc_invocation_data(InvocationData {
-            module: self.resolver.current_module,
-            parent_legacy_scope: self.current_legacy_scope,
+        let invocation_data = self.r.arenas.alloc_invocation_data(InvocationData {
+            module: self.parent_scope.module,
+            parent_legacy_scope: self.parent_scope.legacy,
             output_legacy_scope: Cell::new(None),
         });
-        let old_invocation_data = self.resolver.invocations.insert(invoc_id, invocation_data);
+        let old_invocation_data = self.r.invocations.insert(invoc_id, invocation_data);
         assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation");
 
         invocation_data
     }
+
+    fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
+        if attr::contains_name(&item.attrs, sym::proc_macro) {
+            return Some((MacroKind::Bang, item.ident, item.span));
+        } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
+            return Some((MacroKind::Attr, item.ident, item.span));
+        } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
+            if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
+                if let Some(ident) = nested_meta.ident() {
+                    return Some((MacroKind::Derive, ident, ident.span));
+                }
+            }
+        }
+        None
+    }
+
+    fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> {
+        let parent_scope = &self.parent_scope;
+        let expansion = parent_scope.expansion;
+        let (ext, ident, span, is_legacy) = match &item.node {
+            ItemKind::MacroDef(def) => {
+                let ext = self.r.compile_macro(item, self.r.session.edition());
+                (ext, item.ident, item.span, def.legacy)
+            }
+            ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
+                Some((macro_kind, ident, span)) => {
+                    self.r.proc_macro_stubs.insert(item.id);
+                    (self.r.dummy_ext(macro_kind), ident, span, false)
+                }
+                None => return parent_scope.legacy,
+            }
+            _ => unreachable!(),
+        };
+
+        let def_id = self.r.definitions.local_def_id(item.id);
+        let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
+        self.r.macro_map.insert(def_id, ext);
+        self.r.local_macro_def_scopes.insert(item.id, parent_scope.module);
+
+        if is_legacy {
+            let ident = ident.modern();
+            self.r.macro_names.insert(ident);
+            let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
+            let vis = if is_macro_export {
+                ty::Visibility::Public
+            } else {
+                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+            };
+            let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
+            self.r.set_binding_parent_module(binding, parent_scope.module);
+            self.r.all_macros.insert(ident.name, res);
+            if is_macro_export {
+                let module = self.r.graph_root;
+                self.r.define(module, ident, MacroNS,
+                            (res, vis, span, expansion, IsMacroExport));
+            } else {
+                self.r.check_reserved_macro_name(ident, res);
+                self.r.unused_macros.insert(item.id, span);
+            }
+            LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding {
+                parent_legacy_scope: parent_scope.legacy, binding, ident
+            }))
+        } else {
+            let module = parent_scope.module;
+            let vis = self.resolve_visibility(&item.vis);
+            if vis != ty::Visibility::Public {
+                self.r.unused_macros.insert(item.id, span);
+            }
+            self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
+            self.parent_scope.legacy
+        }
+    }
 }
 
 macro_rules! method {
     ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
-        fn $visit(&mut self, node: &'a $ty) {
+        fn $visit(&mut self, node: &'b $ty) {
             if let $invoc(..) = node.node {
                 self.visit_invoc(node.id);
             } else {
@@ -952,71 +1174,65 @@ macro_rules! method {
     }
 }
 
-impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
     method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
     method!(visit_expr:      ast::Expr,     ast::ExprKind::Mac,       walk_expr);
     method!(visit_pat:       ast::Pat,      ast::PatKind::Mac,        walk_pat);
     method!(visit_ty:        ast::Ty,       ast::TyKind::Mac,         walk_ty);
 
-    fn visit_item(&mut self, item: &'a Item) {
+    fn visit_item(&mut self, item: &'b Item) {
         let macro_use = match item.node {
             ItemKind::MacroDef(..) => {
-                self.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope);
+                self.parent_scope.legacy = self.define_macro(item);
                 return
             }
             ItemKind::Mac(..) => {
-                self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id));
+                self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(item.id));
                 return
             }
-            ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
+            ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
             _ => false,
         };
 
-        let orig_current_module = self.resolver.current_module;
-        let orig_current_legacy_scope = self.current_legacy_scope;
-        let parent_scope = ParentScope {
-            module: self.resolver.current_module,
-            expansion: self.expansion,
-            legacy: self.current_legacy_scope,
-            derives: Vec::new(),
-        };
-        self.resolver.build_reduced_graph_for_item(item, parent_scope);
+        let orig_current_module = self.parent_scope.module;
+        let orig_current_legacy_scope = self.parent_scope.legacy;
+        self.build_reduced_graph_for_item(item);
         visit::walk_item(self, item);
-        self.resolver.current_module = orig_current_module;
+        self.parent_scope.module = orig_current_module;
         if !macro_use {
-            self.current_legacy_scope = orig_current_legacy_scope;
+            self.parent_scope.legacy = orig_current_legacy_scope;
         }
     }
 
-    fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
+    fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
         if let ast::StmtKind::Mac(..) = stmt.node {
-            self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id));
+            self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(stmt.id));
         } else {
             visit::walk_stmt(self, stmt);
         }
     }
 
-    fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
+    fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) {
         if let ForeignItemKind::Macro(_) = foreign_item.node {
             self.visit_invoc(foreign_item.id);
             return;
         }
 
-        self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
+        self.build_reduced_graph_for_foreign_item(foreign_item);
         visit::walk_foreign_item(self, foreign_item);
     }
 
-    fn visit_block(&mut self, block: &'a Block) {
-        let orig_current_module = self.resolver.current_module;
-        let orig_current_legacy_scope = self.current_legacy_scope;
-        self.resolver.build_reduced_graph_for_block(block, self.expansion);
+    fn visit_block(&mut self, block: &'b Block) {
+        let orig_current_module = self.parent_scope.module;
+        let orig_current_legacy_scope = self.parent_scope.legacy;
+        self.build_reduced_graph_for_block(block);
         visit::walk_block(self, block);
-        self.resolver.current_module = orig_current_module;
-        self.current_legacy_scope = orig_current_legacy_scope;
+        self.parent_scope.module = orig_current_module;
+        self.parent_scope.legacy = orig_current_legacy_scope;
     }
 
-    fn visit_trait_item(&mut self, item: &'a TraitItem) {
-        let parent = self.resolver.current_module;
+    fn visit_trait_item(&mut self, item: &'b TraitItem) {
+        let parent = self.parent_scope.module;
 
         if let TraitItemKind::Macro(_) = item.node {
             self.visit_invoc(item.id);
@@ -1024,12 +1240,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
         }
 
         // Add the item to the trait info.
-        let item_def_id = self.resolver.definitions.local_def_id(item.id);
+        let item_def_id = self.r.definitions.local_def_id(item.id);
         let (res, ns) = match item.node {
             TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
             TraitItemKind::Method(ref sig, _) => {
                 if sig.decl.has_self() {
-                    self.resolver.has_self.insert(item_def_id);
+                    self.r.has_self.insert(item_def_id);
                 }
                 (Res::Def(DefKind::Method, item_def_id), ValueNS)
             }
@@ -1038,11 +1254,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
         };
 
         let vis = ty::Visibility::Public;
-        self.resolver.define(parent, item.ident, ns, (res, vis, item.span, self.expansion));
+        let expansion = self.parent_scope.expansion;
+        self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
 
-        self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor
+        self.parent_scope.module = parent.parent.unwrap(); // nearest normal ancestor
         visit::walk_trait_item(self, item);
-        self.resolver.current_module = parent;
+        self.parent_scope.module = parent;
     }
 
     fn visit_token(&mut self, t: Token) {
@@ -1055,17 +1272,10 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
         }
     }
 
-    fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
+    fn visit_attribute(&mut self, attr: &'b ast::Attribute) {
         if !attr.is_sugared_doc && is_builtin_attr(attr) {
-            let parent_scope = ParentScope {
-                module: self.resolver.current_module.nearest_item_scope(),
-                expansion: self.expansion,
-                legacy: self.current_legacy_scope,
-                // Let's hope discerning built-in attributes from derive helpers is not necessary
-                derives: Vec::new(),
-            };
-            parent_scope.module.builtin_attrs.borrow_mut().push((
-                attr.path.segments[0].ident, parent_scope
+            self.parent_scope.module.builtin_attrs.borrow_mut().push((
+                attr.path.segments[0].ident, self.parent_scope.clone()
             ));
         }
         visit::walk_attribute(self, attr);
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 4fee15c59b3..96d44b4b4c0 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -23,8 +23,6 @@
 //  - `check_crate` finally emits the diagnostics based on the data generated
 //    in the last step
 
-use std::ops::{Deref, DerefMut};
-
 use crate::Resolver;
 use crate::resolve_imports::ImportDirectiveSubclass;
 
@@ -49,7 +47,7 @@ impl<'a> UnusedImport<'a> {
 }
 
 struct UnusedImportCheckVisitor<'a, 'b> {
-    resolver: &'a mut Resolver<'b>,
+    r: &'a mut Resolver<'b>,
     /// All the (so far) unused imports, grouped path list
     unused_imports: NodeMap<UnusedImport<'a>>,
     base_use_tree: Option<&'a ast::UseTree>,
@@ -57,29 +55,14 @@ struct UnusedImportCheckVisitor<'a, 'b> {
     item_span: Span,
 }
 
-// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
-impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> {
-    type Target = Resolver<'b>;
-
-    fn deref<'c>(&'c self) -> &'c Resolver<'b> {
-        &*self.resolver
-    }
-}
-
-impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> {
-    fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
-        &mut *self.resolver
-    }
-}
-
 impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
     // We have information about whether `use` (import) directives are actually
     // used now. If an import is not used at all, we signal a lint error.
     fn check_import(&mut self, id: ast::NodeId) {
         let mut used = false;
-        self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
+        self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
         if !used {
-            if self.maybe_unused_trait_imports.contains(&id) {
+            if self.r.maybe_unused_trait_imports.contains(&id) {
                 // Check later.
                 return;
             }
@@ -87,7 +70,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
         } else {
             // This trait import is definitely used, in a way other than
             // method resolution.
-            self.maybe_unused_trait_imports.remove(&id);
+            self.r.maybe_unused_trait_imports.remove(&id);
             if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
                 i.unused.remove(&id);
             }
@@ -238,104 +221,102 @@ fn calc_unused_spans(
     }
 }
 
-pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) {
-    for directive in resolver.potentially_unused_imports.iter() {
-        match directive.subclass {
-            _ if directive.used.get() ||
-                 directive.vis.get() == ty::Visibility::Public ||
-                 directive.span.is_dummy() => {
-                if let ImportDirectiveSubclass::MacroUse = directive.subclass {
-                    if !directive.span.is_dummy() {
-                        resolver.session.buffer_lint(
-                            lint::builtin::MACRO_USE_EXTERN_CRATE,
-                            directive.id,
-                            directive.span,
-                            "deprecated `#[macro_use]` directive used to \
-                             import macros should be replaced at use sites \
-                             with a `use` statement to import the macro \
-                             instead",
-                        );
+impl Resolver<'_> {
+    crate fn check_unused(&mut self, krate: &ast::Crate) {
+        for directive in self.potentially_unused_imports.iter() {
+            match directive.subclass {
+                _ if directive.used.get() ||
+                    directive.vis.get() == ty::Visibility::Public ||
+                    directive.span.is_dummy() => {
+                    if let ImportDirectiveSubclass::MacroUse = directive.subclass {
+                        if !directive.span.is_dummy() {
+                            self.session.buffer_lint(
+                                lint::builtin::MACRO_USE_EXTERN_CRATE,
+                                directive.id,
+                                directive.span,
+                                "deprecated `#[macro_use]` directive used to \
+                                import macros should be replaced at use sites \
+                                with a `use` statement to import the macro \
+                                instead",
+                            );
+                        }
                     }
                 }
+                ImportDirectiveSubclass::ExternCrate { .. } => {
+                    self.maybe_unused_extern_crates.push((directive.id, directive.span));
+                }
+                ImportDirectiveSubclass::MacroUse => {
+                    let lint = lint::builtin::UNUSED_IMPORTS;
+                    let msg = "unused `#[macro_use]` import";
+                    self.session.buffer_lint(lint, directive.id, directive.span, msg);
+                }
+                _ => {}
             }
-            ImportDirectiveSubclass::ExternCrate { .. } => {
-                resolver.maybe_unused_extern_crates.push((directive.id, directive.span));
-            }
-            ImportDirectiveSubclass::MacroUse => {
-                let lint = lint::builtin::UNUSED_IMPORTS;
-                let msg = "unused `#[macro_use]` import";
-                resolver.session.buffer_lint(lint, directive.id, directive.span, msg);
-            }
-            _ => {}
         }
-    }
-
-    for (id, span) in resolver.unused_labels.iter() {
-        resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
-    }
 
-    let mut visitor = UnusedImportCheckVisitor {
-        resolver,
-        unused_imports: Default::default(),
-        base_use_tree: None,
-        base_id: ast::DUMMY_NODE_ID,
-        item_span: DUMMY_SP,
-    };
-    visit::walk_crate(&mut visitor, krate);
-
-    for unused in visitor.unused_imports.values() {
-        let mut fixes = Vec::new();
-        let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
-            UnusedSpanResult::Used => continue,
-            UnusedSpanResult::FlatUnused(span, remove) => {
-                fixes.push((remove, String::new()));
-                vec![span]
-            }
-            UnusedSpanResult::NestedFullUnused(spans, remove) => {
-                fixes.push((remove, String::new()));
-                spans
-            }
-            UnusedSpanResult::NestedPartialUnused(spans, remove) => {
-                for fix in &remove {
-                    fixes.push((*fix, String::new()));
-                }
-                spans
-            }
+        let mut visitor = UnusedImportCheckVisitor {
+            r: self,
+            unused_imports: Default::default(),
+            base_use_tree: None,
+            base_id: ast::DUMMY_NODE_ID,
+            item_span: DUMMY_SP,
         };
+        visit::walk_crate(&mut visitor, krate);
 
-        let len = spans.len();
-        spans.sort();
-        let ms = MultiSpan::from_spans(spans.clone());
-        let mut span_snippets = spans.iter()
-            .filter_map(|s| {
-                match visitor.session.source_map().span_to_snippet(*s) {
-                    Ok(s) => Some(format!("`{}`", s)),
-                    _ => None,
+        for unused in visitor.unused_imports.values() {
+            let mut fixes = Vec::new();
+            let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
+                UnusedSpanResult::Used => continue,
+                UnusedSpanResult::FlatUnused(span, remove) => {
+                    fixes.push((remove, String::new()));
+                    vec![span]
                 }
-            }).collect::<Vec<String>>();
-        span_snippets.sort();
-        let msg = format!("unused import{}{}",
-                          if len > 1 { "s" } else { "" },
-                          if !span_snippets.is_empty() {
-                              format!(": {}", span_snippets.join(", "))
-                          } else {
-                              String::new()
-                          });
+                UnusedSpanResult::NestedFullUnused(spans, remove) => {
+                    fixes.push((remove, String::new()));
+                    spans
+                }
+                UnusedSpanResult::NestedPartialUnused(spans, remove) => {
+                    for fix in &remove {
+                        fixes.push((*fix, String::new()));
+                    }
+                    spans
+                }
+            };
 
-        let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
-            "remove the whole `use` item"
-        } else if spans.len() > 1 {
-            "remove the unused imports"
-        } else {
-            "remove the unused import"
-        };
+            let len = spans.len();
+            spans.sort();
+            let ms = MultiSpan::from_spans(spans.clone());
+            let mut span_snippets = spans.iter()
+                .filter_map(|s| {
+                    match visitor.r.session.source_map().span_to_snippet(*s) {
+                        Ok(s) => Some(format!("`{}`", s)),
+                        _ => None,
+                    }
+                }).collect::<Vec<String>>();
+            span_snippets.sort();
+            let msg = format!("unused import{}{}",
+                            if len > 1 { "s" } else { "" },
+                            if !span_snippets.is_empty() {
+                                format!(": {}", span_snippets.join(", "))
+                            } else {
+                                String::new()
+                            });
 
-        visitor.session.buffer_lint_with_diagnostic(
-            lint::builtin::UNUSED_IMPORTS,
-            unused.use_tree_id,
-            ms,
-            &msg,
-            lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
-        );
+            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
+                "remove the whole `use` item"
+            } else if spans.len() > 1 {
+                "remove the unused imports"
+            } else {
+                "remove the unused import"
+            };
+
+            visitor.r.session.buffer_lint_with_diagnostic(
+                lint::builtin::UNUSED_IMPORTS,
+                unused.use_tree_id,
+                ms,
+                &msg,
+                lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
+            );
+        }
     }
 }
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index aeb6f23da5a..01a4a3c4bb2 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -2,55 +2,63 @@ use std::cmp::Reverse;
 
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use log::debug;
-use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind};
+use rustc::bug;
+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::source_map::SourceMap;
+use syntax::struct_span_err;
 use syntax::symbol::{Symbol, kw};
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{BytePos, Span};
+use syntax_pos::{BytePos, Span, MultiSpan};
 
 use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
-use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS};
-use crate::{CrateLint, 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, ResolutionError, 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(
+/// Adjust the impl span so that just the `impl` keyword is taken by removing
+/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
+/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
+///
+/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
+/// parser. If you need to use this function or something similar, please consider updating the
+/// `source_map` functions and this function to something more robust.
+fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
+    let impl_span = cm.span_until_char(impl_span, '<');
+    let impl_span = cm.span_until_whitespace(impl_span);
+    impl_span
+}
+
+crate fn add_typo_suggestion(
     err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
 ) -> bool {
     if let Some(suggestion) = suggestion {
@@ -65,7 +73,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() {
@@ -79,479 +87,267 @@ fn add_module_candidates(
 }
 
 impl<'a> Resolver<'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_without_parent_scope(
-                    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);
+    /// Combines an error with provided span and emits it.
+    ///
+    /// This takes the error provided, combines it with the span and any additional spans inside the
+    /// error and emits it.
+    crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+        self.into_struct_error(span, resolution_error).emit();
+    }
 
-                err.span_suggestions(
+    crate fn into_struct_error(
+        &self, span: Span, resolution_error: ResolutionError<'_>
+    ) -> DiagnosticBuilder<'_> {
+        match resolution_error {
+            ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
+                let mut err = struct_span_err!(self.session,
                     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,
+                    E0401,
+                    "can't use generic parameters from outer function",
                 );
-            }
-        }
-        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, format!("use of generic parameter from outer function"));
+
+                let cm = self.session.source_map();
+                match outer_res {
+                    Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
+                        if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
+                            self.definitions.opt_span(def_id)
+                        }) {
                             err.span_label(
-                                span,
-                                "a field by this name exists in `Self`",
+                                reduce_impl_span_to_impl_keyword(cm, impl_span),
+                                "`Self` type implicitly declared here, by this `impl`",
                             );
                         }
+                        match (maybe_trait_defid, maybe_impl_defid) {
+                            (Some(_), None) => {
+                                err.span_label(span, "can't use `Self` here");
+                            }
+                            (_, Some(_)) => {
+                                err.span_label(span, "use a type here instead");
+                            }
+                            (None, None) => bug!("`impl` without trait nor type?"),
+                        }
+                        return err;
+                    },
+                    Res::Def(DefKind::TyParam, def_id) => {
+                        if let Some(span) = self.definitions.opt_span(def_id) {
+                            err.span_label(span, "type parameter from outer function");
+                        }
                     }
-                    AssocSuggestion::MethodWithSelf if self_is_available => {
-                        err.span_suggestion(
-                            span,
-                            "try",
-                            format!("self.{}", path_str),
-                            Applicability::MachineApplicable,
-                        );
+                    Res::Def(DefKind::ConstParam, def_id) => {
+                        if let Some(span) = self.definitions.opt_span(def_id) {
+                            err.span_label(span, "const parameter from outer function");
+                        }
                     }
-                    AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
-                        err.span_suggestion(
-                            span,
-                            "try",
-                            format!("Self::{}", path_str),
-                            Applicability::MachineApplicable,
-                        );
+                    _ => {
+                        bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
+                            DefKind::TyParam");
                     }
                 }
-                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 to retrieve the span of the function signature and generate a new message
+                // with a local type or const parameter.
+                let sugg_msg = &format!("try using a local generic parameter instead");
+                if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
+                    // Suggest the modification to the user
+                    err.span_suggestion(
+                        sugg_span,
+                        sugg_msg,
+                        new_snippet,
+                        Applicability::MachineApplicable,
+                    );
+                } else if let Some(sp) = cm.generate_fn_name_span(span) {
+                    err.span_label(sp,
+                        format!("try adding a local generic parameter in this method instead"));
+                } else {
+                    err.help(&format!("try using a local generic parameter instead"));
+                }
 
-        // 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);
+                err
             }
-        }
-
-        // 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,
+            ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
+                let mut err = struct_span_err!(self.session,
+                                                span,
+                                                E0403,
+                                                "the name `{}` is already used for a generic \
+                                                parameter in this list of generic parameters",
+                                                name);
+                err.span_label(span, "already used");
+                err.span_label(first_use_span, format!("first use of `{}`", name));
+                err
             }
-        }
-        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,
+            ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0407,
+                                            "method `{}` is not a member of trait `{}`",
+                                            method,
+                                            trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
             }
-            i += 1;
-            // The bigger the span, the more likely we're incorrect --
-            // bound it to 100 chars long.
-            if i > 100 {
-                break;
+            ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0437,
+                                "type `{}` is not a member of trait `{}`",
+                                type_,
+                                trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
             }
-        }
-        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
+            ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0438,
+                                "const `{}` is not a member of trait `{}`",
+                                const_,
+                                trait_);
+                err.span_label(span, format!("not a member of trait `{}`", trait_));
+                err
             }
-            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,
+            ResolutionError::VariableNotBoundInPattern(binding_error) => {
+                let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
+                let msp = MultiSpan::from_spans(target_sp.clone());
+                let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
+                let mut err = self.session.struct_span_err_with_code(
+                    msp,
+                    &msg,
+                    DiagnosticId::Error("E0408".into()),
                 );
-                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);
+                for sp in target_sp {
+                    err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
                 }
-                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");
+                let origin_sp = binding_error.origin.iter().cloned();
+                for sp in origin_sp {
+                    err.span_label(sp, "variable not in all patterns");
                 }
+                err
             }
-            (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?");
-                }
+            ResolutionError::VariableBoundWithDifferentMode(variable_name,
+                                                            first_binding_span) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0409,
+                                "variable `{}` is bound in inconsistent \
+                                ways within the same match arm",
+                                variable_name);
+                err.span_label(span, "bound in different ways");
+                err.span_label(first_binding_span, "first binding");
+                err
             }
-            (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
-                if !path_sep(err, &parent) {
-                    return false;
-                }
+            ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0415,
+                                "identifier `{}` is bound more than once in this parameter list",
+                                identifier);
+                err.span_label(span, "used as parameter more than once");
+                err
             }
-            (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(ctor_vis);
-                    if is_expected(ctor_def) && !accessible_ctor {
-                        err.span_label(
-                            span,
-                            format!("constructor is not visible here due to private fields"),
-                        );
-                    }
+            ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
+                let mut err = struct_span_err!(self.session,
+                                span,
+                                E0416,
+                                "identifier `{}` is bound more than once in the same pattern",
+                                identifier);
+                err.span_label(span, "used in a pattern more than once");
+                err
+            }
+            ResolutionError::UndeclaredLabel(name, lev_candidate) => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0426,
+                                            "use of undeclared label `{}`",
+                                            name);
+                if let Some(lev_candidate) = lev_candidate {
+                    err.span_suggestion(
+                        span,
+                        "a label with a similar name exists in this scope",
+                        lev_candidate.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
                 } else {
-                    bad_struct_syntax_suggestion();
+                    err.span_label(span, format!("undeclared label `{}`", name));
                 }
+                err
             }
-            (Res::Def(DefKind::Union, _), _) |
-            (Res::Def(DefKind::Variant, _), _) |
-            (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => {
-                bad_struct_syntax_suggestion();
+            ResolutionError::SelfImportsOnlyAllowedWithin => {
+                struct_span_err!(self.session,
+                                span,
+                                E0429,
+                                "{}",
+                                "`self` imports are only allowed within a { } list")
             }
-            (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");
+            ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
+                let mut err = struct_span_err!(self.session, span, E0430,
+                                            "`self` import can only appear once in an import list");
+                err.span_label(span, "can only appear once in an import list");
+                err
             }
-            (Res::Def(DefKind::TyAlias, _), _)
-            | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => {
-                err.note("can't use a type alias as a constructor");
+            ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
+                let mut err = struct_span_err!(self.session, span, E0431,
+                                            "`self` import can only appear in an import list with \
+                                                a non-empty prefix");
+                err.span_label(span, "can only appear in an import list with a non-empty prefix");
+                err
             }
-            _ => return false,
-        }
-        true
-    }
+            ResolutionError::FailedToResolve { label, suggestion } => {
+                let mut err = struct_span_err!(self.session, span, E0433,
+                                            "failed to resolve: {}", &label);
+                err.span_label(span, label);
 
-    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);
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
+                if let Some((suggestions, msg, applicability)) = suggestion {
+                    err.multipart_suggestion(&msg, suggestions, applicability);
                 }
-            }
-        }
 
-        for assoc_type_ident in &self.current_trait_assoc_types {
-            if *assoc_type_ident == ident {
-                return Some(AssocSuggestion::AssocItem);
+                err
             }
-        }
-
-        // Look for associated items in the current trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            if let Ok(binding) = self.resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    None,
-                    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
-                    });
-                }
+            ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
+                let mut err = struct_span_err!(self.session,
+                                            span,
+                                            E0434,
+                                            "{}",
+                                            "can't capture dynamic environment in a fn item");
+                err.help("use the `|| { ... }` closure form instead");
+                err
+            }
+            ResolutionError::AttemptToUseNonConstantValueInConstant => {
+                let mut err = struct_span_err!(self.session, span, E0435,
+                                            "attempt to use a non-constant value in a constant");
+                err.span_label(span, "non-constant value");
+                err
+            }
+            ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
+                let shadows_what = binding.descr();
+                let mut err = struct_span_err!(self.session, span, E0530, "{}s cannot shadow {}s",
+                                            what_binding, shadows_what);
+                err.span_label(span, format!("cannot be named the same as {} {}",
+                                            binding.article(), shadows_what));
+                let participle = if binding.is_import() { "imported" } else { "defined" };
+                let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
+                err.span_label(binding.span, msg);
+                err
+            }
+            ResolutionError::ForwardDeclaredTyParam => {
+                let mut err = struct_span_err!(self.session, span, E0128,
+                                            "type parameters with a default cannot use \
+                                                forward declared identifiers");
+                err.span_label(
+                    span, "defaulted type parameters cannot be forward declared".to_string());
+                err
+            }
+            ResolutionError::ConstParamDependentOnTypeParam => {
+                let mut err = struct_span_err!(
+                    self.session,
+                    span,
+                    E0671,
+                    "const parameters cannot depend on type parameters"
+                );
+                err.span_label(span, format!("const parameter depends on type parameter"));
+                err
             }
         }
-
-        None
     }
 
     /// Lookup typo candidate in scope for a macro or import.
@@ -569,9 +365,10 @@ impl<'a> Resolver<'a> {
                     let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
                     if filter_fn(res) {
                         for derive in &parent_scope.derives {
-                            let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
+                            let parent_scope =
+                                &ParentScope { derives: Vec::new(), ..*parent_scope };
                             if let Ok((Some(ext), _)) = this.resolve_macro_path(
-                                derive, Some(MacroKind::Derive), &parent_scope, false, false
+                                derive, Some(MacroKind::Derive), parent_scope, false, false
                             ) {
                                 suggestions.extend(ext.helper_attrs.iter().map(|name| {
                                     TypoSuggestion::from_res(*name, res)
@@ -683,98 +480,6 @@ impl<'a> Resolver<'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_without_parent_scope(
-                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,
-        }
-    }
-
     fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                                           lookup_ident: Ident,
                                           namespace: Namespace,
@@ -901,65 +606,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>,
@@ -969,7 +615,7 @@ impl<'a> Resolver<'a> {
     ) {
         let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
         let suggestion = self.early_lookup_typo_candidate(
-            ScopeSet::Macro(macro_kind), &parent_scope, ident, is_expected
+            ScopeSet::Macro(macro_kind), parent_scope, ident, is_expected
         );
         add_typo_suggestion(err, suggestion, ident.span);
 
@@ -1029,7 +675,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
-        let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
+        let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((path, Vec::new()))
@@ -1053,7 +699,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
-        let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
+        let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((
@@ -1084,7 +730,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
-        let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
+        let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((path, Vec::new()))
@@ -1117,13 +763,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         // 1) some consistent ordering for emitted dignostics, and
         // 2) `std` suggestions before `core` suggestions.
         let mut extern_crate_names =
-            self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
+            self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
         extern_crate_names.sort_by_key(|name| Reverse(name.as_str()));
 
         for name in extern_crate_names.into_iter() {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
-            let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
+            let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
             debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
                     name, path, result);
             if let PathResult::Module(..) = result {
@@ -1189,7 +835,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 //   ie. `use a::b::{c, d, e};`
                 //                      ^^^
                 let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
-                    self.resolver.session, directive.span, directive.use_span,
+                    self.r.session, directive.span, directive.use_span,
                 );
                 debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
                        found_closing_brace, binding_span);
@@ -1204,7 +850,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     //   ie. `use a::b::{c, d};`
                     //                    ^^^
                     if let Some(previous_span) = extend_span_to_previous_binding(
-                        self.resolver.session, binding_span,
+                        self.r.session, binding_span,
                     ) {
                         debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
                         removal_span = removal_span.with_lo(previous_span.lo());
@@ -1222,12 +868,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 //   or  `use a::{b, c, d}};`
                 //               ^^^^^^^^^^^
                 let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
-                    self.resolver.session, module_name, directive.use_span,
+                    self.r.session, module_name, directive.use_span,
                 );
                 debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
                        has_nested, after_crate_name);
 
-                let source_map = self.resolver.session.source_map();
+                let source_map = self.r.session.source_map();
 
                 // Add the import to the start, with a `{` if required.
                 let start_point = source_map.start_point(after_crate_name);
@@ -1415,21 +1061,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..7cb11195ee0
--- /dev/null
+++ b/src/librustc_resolve/late.rs
@@ -0,0 +1,2004 @@
+use GenericParameters::*;
+use RibKind::*;
+
+use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
+use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
+use crate::{ResolutionError, Resolver, Segment, UseError};
+
+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;
+
+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",
+        }
+    }
+}
+
+/// The rib kind restricts certain accesses,
+/// e.g. to a `Res::Local` of an outer item.
+#[derive(Copy, Clone, Debug)]
+crate enum RibKind<'a> {
+    /// No restriction needs to be applied.
+    NormalRibKind,
+
+    /// We passed through an impl or trait and are now in one of its
+    /// methods or associated types. Allow references to ty params that impl or trait
+    /// binds. Disallow any other upvars (including other ty params that are
+    /// upvars).
+    AssocItemRibKind,
+
+    /// We passed through a function definition. Disallow upvars.
+    /// Permit only those const parameters that are specified in the function's generics.
+    FnItemRibKind,
+
+    /// We passed through an item scope. Disallow upvars.
+    ItemRibKind,
+
+    /// We're in a constant item. Can't refer to dynamic stuff.
+    ConstantItemRibKind,
+
+    /// We passed through a module.
+    ModuleRibKind(Module<'a>),
+
+    /// We passed through a `macro_rules!` statement
+    MacroDefinition(DefId),
+
+    /// All bindings in this rib are type parameters that can't be used
+    /// from the default of a type parameter because they're not declared
+    /// before said type parameter. Also see the `visit_generics` override.
+    ForwardTyParamBanRibKind,
+
+    /// We forbid the use of type parameters as the types of const parameters.
+    TyParamAsConstParamTy,
+}
+
+/// A single local scope.
+///
+/// A rib represents a scope names can live in. Note that these appear in many places, not just
+/// around braces. At any place where the list of accessible names (of the given namespace)
+/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a
+/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
+/// etc.
+///
+/// Different [rib kinds](enum.RibKind) are transparent for different names.
+///
+/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
+/// resolving, the name is looked up from inside out.
+#[derive(Debug)]
+crate struct Rib<'a, R = Res> {
+    pub bindings: FxHashMap<Ident, R>,
+    pub kind: RibKind<'a>,
+}
+
+impl<'a, R> Rib<'a, R> {
+    fn new(kind: RibKind<'a>) -> Rib<'a, R> {
+        Rib {
+            bindings: Default::default(),
+            kind,
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+crate enum AliasPossibility {
+    No,
+    Maybe,
+}
+
+#[derive(Copy, Clone, Debug)]
+crate enum PathSource<'a> {
+    // Type paths `Path`.
+    Type,
+    // Trait paths in bounds or impls.
+    Trait(AliasPossibility),
+    // Expression paths `path`, with optional parent context.
+    Expr(Option<&'a Expr>),
+    // Paths in path patterns `Path`.
+    Pat,
+    // Paths in struct expressions and patterns `Path { .. }`.
+    Struct,
+    // Paths in tuple struct patterns `Path(..)`.
+    TupleStruct,
+    // `m::A::B` in `<T as m::A>::B::C`.
+    TraitItem(Namespace),
+}
+
+impl<'a> PathSource<'a> {
+    fn namespace(self) -> Namespace {
+        match self {
+            PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
+            PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
+            PathSource::TraitItem(ns) => ns,
+        }
+    }
+
+    fn defer_to_typeck(self) -> bool {
+        match self {
+            PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+            PathSource::Struct | PathSource::TupleStruct => true,
+            PathSource::Trait(_) | PathSource::TraitItem(..) => false,
+        }
+    }
+
+    fn descr_expected(self) -> &'static str {
+        match self {
+            PathSource::Type => "type",
+            PathSource::Trait(_) => "trait",
+            PathSource::Pat => "unit struct/variant or constant",
+            PathSource::Struct => "struct, variant or union type",
+            PathSource::TupleStruct => "tuple struct/variant",
+            PathSource::TraitItem(ns) => match ns {
+                TypeNS => "associated type",
+                ValueNS => "method or associated constant",
+                MacroNS => bug!("associated macro"),
+            },
+            PathSource::Expr(parent) => match parent.map(|p| &p.node) {
+                // "function" here means "anything callable" rather than `DefKind::Fn`,
+                // this is not precise but usually more helpful than just "value".
+                Some(&ExprKind::Call(..)) => "function",
+                _ => "value",
+            },
+        }
+    }
+
+    crate fn is_expected(self, res: Res) -> bool {
+        match self {
+            PathSource::Type => match res {
+                Res::Def(DefKind::Struct, _)
+                | Res::Def(DefKind::Union, _)
+                | Res::Def(DefKind::Enum, _)
+                | Res::Def(DefKind::Trait, _)
+                | Res::Def(DefKind::TraitAlias, _)
+                | Res::Def(DefKind::TyAlias, _)
+                | Res::Def(DefKind::AssocTy, _)
+                | Res::PrimTy(..)
+                | Res::Def(DefKind::TyParam, _)
+                | Res::SelfTy(..)
+                | Res::Def(DefKind::OpaqueTy, _)
+                | Res::Def(DefKind::ForeignTy, _) => true,
+                _ => false,
+            },
+            PathSource::Trait(AliasPossibility::No) => match res {
+                Res::Def(DefKind::Trait, _) => true,
+                _ => false,
+            },
+            PathSource::Trait(AliasPossibility::Maybe) => match res {
+                Res::Def(DefKind::Trait, _) => true,
+                Res::Def(DefKind::TraitAlias, _) => true,
+                _ => false,
+            },
+            PathSource::Expr(..) => match res {
+                Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
+                | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+                | Res::Def(DefKind::Const, _)
+                | Res::Def(DefKind::Static, _)
+                | Res::Local(..)
+                | Res::Def(DefKind::Fn, _)
+                | Res::Def(DefKind::Method, _)
+                | Res::Def(DefKind::AssocConst, _)
+                | Res::SelfCtor(..)
+                | Res::Def(DefKind::ConstParam, _) => true,
+                _ => false,
+            },
+            PathSource::Pat => match res {
+                Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
+                Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
+                Res::SelfCtor(..) => true,
+                _ => false,
+            },
+            PathSource::TupleStruct => match res {
+                Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
+                _ => false,
+            },
+            PathSource::Struct => match res {
+                Res::Def(DefKind::Struct, _)
+                | Res::Def(DefKind::Union, _)
+                | Res::Def(DefKind::Variant, _)
+                | Res::Def(DefKind::TyAlias, _)
+                | Res::Def(DefKind::AssocTy, _)
+                | Res::SelfTy(..) => true,
+                _ => false,
+            },
+            PathSource::TraitItem(ns) => match res {
+                Res::Def(DefKind::AssocConst, _)
+                | Res::Def(DefKind::Method, _) if ns == ValueNS => true,
+                Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
+                _ => false,
+            },
+        }
+    }
+
+    fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
+        __diagnostic_used!(E0404);
+        __diagnostic_used!(E0405);
+        __diagnostic_used!(E0412);
+        __diagnostic_used!(E0422);
+        __diagnostic_used!(E0423);
+        __diagnostic_used!(E0425);
+        __diagnostic_used!(E0531);
+        __diagnostic_used!(E0532);
+        __diagnostic_used!(E0573);
+        __diagnostic_used!(E0574);
+        __diagnostic_used!(E0575);
+        __diagnostic_used!(E0576);
+        match (self, has_unexpected_resolution) {
+            (PathSource::Trait(_), true) => "E0404",
+            (PathSource::Trait(_), false) => "E0405",
+            (PathSource::Type, true) => "E0573",
+            (PathSource::Type, false) => "E0412",
+            (PathSource::Struct, true) => "E0574",
+            (PathSource::Struct, false) => "E0422",
+            (PathSource::Expr(..), true) => "E0423",
+            (PathSource::Expr(..), false) => "E0425",
+            (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
+            (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
+            (PathSource::TraitItem(..), true) => "E0575",
+            (PathSource::TraitItem(..), false) => "E0576",
+        }
+    }
+}
+
+struct LateResolutionVisitor<'a, 'b> {
+    r: &'b mut Resolver<'a>,
+
+    /// The module that represents the current item scope.
+    parent_scope: ParentScope<'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>,
+}
+
+/// 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.r.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> {
+        // During late resolution we only track the module component of the parent scope,
+        // although it may be useful to track other components as well for diagnostics.
+        let parent_scope = resolver.dummy_parent_scope();
+        let graph_root = resolver.graph_root;
+        LateResolutionVisitor {
+            r: resolver,
+            parent_scope,
+            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 resolve_ident_in_lexical_scope(&mut self,
+                                      ident: Ident,
+                                      ns: Namespace,
+                                      record_used_id: Option<NodeId>,
+                                      path_span: Span)
+                                      -> Option<LexicalScopeBinding<'a>> {
+        self.r.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.r.resolve_path_with_ribs(
+            path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&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 `parent_scope.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.r.definitions.local_def_id(id);
+        let module = self.r.module_map.get(&id).cloned(); // clones a reference
+        if let Some(module) = module {
+            // Move down in the graph.
+            let orig_module = replace(&mut self.parent_scope.module, module);
+            self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
+            self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
+
+            self.r.finalize_current_module_macro_resolutions(module);
+            let ret = f(self);
+
+            self.parent_scope.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.r.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.r.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.r.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.r.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.r.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.r.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.r.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,
+                                );
+                                self.r.report_error(param.ident.span, err);
+                            }
+                            seen_bindings.entry(ident).or_insert(param.ident.span);
+
+                            // Plain insert (no renaming).
+                            let res = Res::Def(
+                                DefKind::TyParam,
+                                self.r.definitions.local_def_id(param.id),
+                            );
+                            function_type_rib.bindings.insert(ident, res);
+                            self.r.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,
+                                );
+                                self.r.report_error(param.ident.span, err);
+                            }
+                            seen_bindings.entry(ident).or_insert(param.ident.span);
+
+                            let res = Res::Def(
+                                DefKind::ConstParam,
+                                self.r.definitions.local_def_id(param.id),
+                            );
+                            function_value_rib.bindings.insert(ident, res);
+                            self.r.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.r.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 {
+                                    // 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 {
+            if self.r.resolve_ident_in_module(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                &self.parent_scope,
+                false,
+                span,
+            ).is_err() {
+                let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+                self.r.report_error(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.r.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 {
+            self.r.report_error(
+                *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 {
+            self.r.report_error(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.parent_scope.module;
+        let anonymous_module = self.r.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.parent_scope.module = anonymous_module;
+            self.r.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.r.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.parent_scope.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
+                self.r.report_error(
+                    ident.span,
+                    ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
+                        &ident.as_str())
+                );
+            }
+            Some(..) if pat_src == PatternSource::FnParam => {
+                // `fn f(a: u8, a: u8)`, error
+                self.r.report_error(
+                    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.r.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.
+                                self.r.report_error(
+                                    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.r.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.parent_scope.module.normal_ancestor_id;
+            let node_id = this.r.definitions.as_local_node_id(def_id).unwrap();
+            let better = res.is_some();
+            this.r.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.r.struct_constructors.get(&def_id).cloned() {
+                            if is_expected(ctor_res) &&
+                               self.r.is_accessible_from(ctor_vis, self.parent_scope.module) {
+                                let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
+                                self.r.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.r.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.r.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.r.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.r.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 };
+            if let Ok((_, res)) = self.r.resolve_macro_path(
+                &path, None, &self.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.r.primitive_type_table.primitive_types
+                           .contains_key(&path[0].ident.name) => {
+                let prim = self.r.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 } => {
+                self.r.report_error(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.r.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.r.record_partial_res(expr.id, PartialRes::new(Res::Err));
+                        self.r.report_error(
+                            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.r.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.r.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.r.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 {
+            if self.r.resolve_ident_in_module(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                &self.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.parent_scope.module;
+        loop {
+            self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
+            search_module = unwrap_or!(
+                self.r.hygienic_lexical_parent(search_module, &mut ident.span), break
+            );
+        }
+
+        if let Some(prelude) = self.r.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
+                }
+                if self.r.resolve_ident_in_module_unadjusted(
+                    ModuleOrUniformRoot::Module(module),
+                    ident,
+                    ns,
+                    &self.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.r.maybe_unused_trait_imports.insert(directive.id);
+            self.r.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) {
+        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");
+        }
+    }
+}
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
new file mode 100644
index 00000000000..35cf720ad87
--- /dev/null
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -0,0 +1,770 @@
+use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{PathResult, PathSource, 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, RibKind};
+
+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.r.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.r.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.r.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.r.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.r.struct_constructors.get(&def_id).cloned() {
+                    let accessible_ctor =
+                        self.r.is_accessible_from(ctor_vis, self.parent_scope.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.r.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.r.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 {
+            if let Ok(binding) = self.r.resolve_ident_in_module(
+                    ModuleOrUniformRoot::Module(module),
+                    ident,
+                    ns,
+                    &self.parent_scope,
+                    false,
+                    module.span,
+                ) {
+                let res = binding.res();
+                if filter_fn(res) {
+                    return Some(if self.r.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 {
+                            let extern_prelude = self.r.extern_prelude.clone();
+                            names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
+                                self.r.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.r.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.r.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.r.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.r.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.r.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.r.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.r.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 ce2bc79ff60..e786e102002 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![feature(crate_visibility_modifier)]
@@ -13,60 +11,48 @@
 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};
 use rustc::middle::cstore::CrateStore;
 use rustc::session::Session;
 use rustc::lint;
-use rustc::hir::def::{
-    self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap
-};
+use rustc::hir::def::{self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap};
 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};
+use rustc::span_bug;
 
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::CStore;
 
-use syntax::source_map::SourceMap;
 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};
+use syntax::ast::{ItemKind, Path};
+use syntax::{struct_span_err, unwrap_or};
 
-use syntax_pos::{Span, DUMMY_SP, MultiSpan};
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use syntax_pos::{Span, DUMMY_SP};
+use errors::{Applicability, DiagnosticBuilder};
 
 use log::debug;
 
 use std::cell::{Cell, RefCell};
-use std::{cmp, fmt, iter, mem, ptr};
+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};
+use late::{PathSource, Rib, RibKind::*};
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
 use macros::{InvocationData, LegacyBinding, LegacyScope};
 
@@ -76,6 +62,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;
@@ -123,10 +110,12 @@ enum Scope<'a> {
 /// This enum is currently used only for early resolution (imports and macros),
 /// but not for late resolution yet.
 enum ScopeSet {
-    Import(Namespace),
+    /// All scopes with the given namespace.
+    All(Namespace, /*is_import*/ bool),
+    /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
     AbsolutePath(Namespace),
+    /// All scopes with macro namespace and the given macro kind restriction.
     Macro(MacroKind),
-    Module,
 }
 
 /// Everything you need to know about a name's location to resolve it.
@@ -208,494 +197,6 @@ enum ResolutionError<'a> {
     ConstParamDependentOnTypeParam,
 }
 
-/// Combines an error with provided span and emits it.
-///
-/// This takes the error provided, combines it with the span and any additional spans inside the
-/// error and emits it.
-fn resolve_error(resolver: &Resolver<'_>,
-                 span: Span,
-                 resolution_error: ResolutionError<'_>) {
-    resolve_struct_error(resolver, span, resolution_error).emit();
-}
-
-fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
-                                   span: Span,
-                                   resolution_error: ResolutionError<'a>)
-                                   -> DiagnosticBuilder<'sess> {
-    match resolution_error {
-        ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
-            let mut err = struct_span_err!(resolver.session,
-                span,
-                E0401,
-                "can't use generic parameters from outer function",
-            );
-            err.span_label(span, format!("use of generic parameter from outer function"));
-
-            let cm = resolver.session.source_map();
-            match outer_res {
-                Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
-                    if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
-                        resolver.definitions.opt_span(def_id)
-                    }) {
-                        err.span_label(
-                            reduce_impl_span_to_impl_keyword(cm, impl_span),
-                            "`Self` type implicitly declared here, by this `impl`",
-                        );
-                    }
-                    match (maybe_trait_defid, maybe_impl_defid) {
-                        (Some(_), None) => {
-                            err.span_label(span, "can't use `Self` here");
-                        }
-                        (_, Some(_)) => {
-                            err.span_label(span, "use a type here instead");
-                        }
-                        (None, None) => bug!("`impl` without trait nor type?"),
-                    }
-                    return err;
-                },
-                Res::Def(DefKind::TyParam, def_id) => {
-                    if let Some(span) = resolver.definitions.opt_span(def_id) {
-                        err.span_label(span, "type parameter from outer function");
-                    }
-                }
-                Res::Def(DefKind::ConstParam, def_id) => {
-                    if let Some(span) = resolver.definitions.opt_span(def_id) {
-                        err.span_label(span, "const parameter from outer function");
-                    }
-                }
-                _ => {
-                    bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
-                         DefKind::TyParam");
-                }
-            }
-
-            // Try to retrieve the span of the function signature and generate a new message with
-            // a local type or const parameter.
-            let sugg_msg = &format!("try using a local generic parameter instead");
-            if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
-                // Suggest the modification to the user
-                err.span_suggestion(
-                    sugg_span,
-                    sugg_msg,
-                    new_snippet,
-                    Applicability::MachineApplicable,
-                );
-            } else if let Some(sp) = cm.generate_fn_name_span(span) {
-                err.span_label(sp,
-                    format!("try adding a local generic parameter in this method instead"));
-            } else {
-                err.help(&format!("try using a local generic parameter instead"));
-            }
-
-            err
-        }
-        ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
-             let mut err = struct_span_err!(resolver.session,
-                                            span,
-                                            E0403,
-                                            "the name `{}` is already used for a generic \
-                                            parameter in this list of generic parameters",
-                                            name);
-             err.span_label(span, "already used");
-             err.span_label(first_use_span, format!("first use of `{}`", name));
-             err
-        }
-        ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0407,
-                                           "method `{}` is not a member of trait `{}`",
-                                           method,
-                                           trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0437,
-                             "type `{}` is not a member of trait `{}`",
-                             type_,
-                             trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0438,
-                             "const `{}` is not a member of trait `{}`",
-                             const_,
-                             trait_);
-            err.span_label(span, format!("not a member of trait `{}`", trait_));
-            err
-        }
-        ResolutionError::VariableNotBoundInPattern(binding_error) => {
-            let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
-            let msp = MultiSpan::from_spans(target_sp.clone());
-            let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
-            let mut err = resolver.session.struct_span_err_with_code(
-                msp,
-                &msg,
-                DiagnosticId::Error("E0408".into()),
-            );
-            for sp in target_sp {
-                err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
-            }
-            let origin_sp = binding_error.origin.iter().cloned();
-            for sp in origin_sp {
-                err.span_label(sp, "variable not in all patterns");
-            }
-            err
-        }
-        ResolutionError::VariableBoundWithDifferentMode(variable_name,
-                                                        first_binding_span) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0409,
-                             "variable `{}` is bound in inconsistent \
-                             ways within the same match arm",
-                             variable_name);
-            err.span_label(span, "bound in different ways");
-            err.span_label(first_binding_span, "first binding");
-            err
-        }
-        ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0415,
-                             "identifier `{}` is bound more than once in this parameter list",
-                             identifier);
-            err.span_label(span, "used as parameter more than once");
-            err
-        }
-        ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0416,
-                             "identifier `{}` is bound more than once in the same pattern",
-                             identifier);
-            err.span_label(span, "used in a pattern more than once");
-            err
-        }
-        ResolutionError::UndeclaredLabel(name, lev_candidate) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0426,
-                                           "use of undeclared label `{}`",
-                                           name);
-            if let Some(lev_candidate) = lev_candidate {
-                err.span_suggestion(
-                    span,
-                    "a label with a similar name exists in this scope",
-                    lev_candidate.to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.span_label(span, format!("undeclared label `{}`", name));
-            }
-            err
-        }
-        ResolutionError::SelfImportsOnlyAllowedWithin => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0429,
-                             "{}",
-                             "`self` imports are only allowed within a { } list")
-        }
-        ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
-            let mut err = struct_span_err!(resolver.session, span, E0430,
-                                           "`self` import can only appear once in an import list");
-            err.span_label(span, "can only appear once in an import list");
-            err
-        }
-        ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
-            let mut err = struct_span_err!(resolver.session, span, E0431,
-                                           "`self` import can only appear in an import list with \
-                                            a non-empty prefix");
-            err.span_label(span, "can only appear in an import list with a non-empty prefix");
-            err
-        }
-        ResolutionError::FailedToResolve { label, suggestion } => {
-            let mut err = struct_span_err!(resolver.session, span, E0433,
-                                           "failed to resolve: {}", &label);
-            err.span_label(span, label);
-
-            if let Some((suggestions, msg, applicability)) = suggestion {
-                err.multipart_suggestion(&msg, suggestions, applicability);
-            }
-
-            err
-        }
-        ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0434,
-                                           "{}",
-                                           "can't capture dynamic environment in a fn item");
-            err.help("use the `|| { ... }` closure form instead");
-            err
-        }
-        ResolutionError::AttemptToUseNonConstantValueInConstant => {
-            let mut err = struct_span_err!(resolver.session, span, E0435,
-                                           "attempt to use a non-constant value in a constant");
-            err.span_label(span, "non-constant value");
-            err
-        }
-        ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
-            let shadows_what = binding.descr();
-            let mut err = struct_span_err!(resolver.session, span, E0530, "{}s cannot shadow {}s",
-                                           what_binding, shadows_what);
-            err.span_label(span, format!("cannot be named the same as {} {}",
-                                         binding.article(), shadows_what));
-            let participle = if binding.is_import() { "imported" } else { "defined" };
-            let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
-            err.span_label(binding.span, msg);
-            err
-        }
-        ResolutionError::ForwardDeclaredTyParam => {
-            let mut err = struct_span_err!(resolver.session, span, E0128,
-                                           "type parameters with a default cannot use \
-                                            forward declared identifiers");
-            err.span_label(
-                span, "defaulted type parameters cannot be forward declared".to_string());
-            err
-        }
-        ResolutionError::ConstParamDependentOnTypeParam => {
-            let mut err = struct_span_err!(
-                resolver.session,
-                span,
-                E0671,
-                "const parameters cannot depend on type parameters"
-            );
-            err.span_label(span, format!("const parameter depends on type parameter"));
-            err
-        }
-    }
-}
-
-/// Adjust the impl span so that just the `impl` keyword is taken by removing
-/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
-/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
-///
-/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
-/// parser. If you need to use this function or something similar, please consider updating the
-/// `source_map` functions and this function to something more robust.
-fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
-    let impl_span = cm.span_until_char(impl_span, '<');
-    let impl_span = cm.span_until_whitespace(impl_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,
-    Maybe,
-}
-
-#[derive(Copy, Clone, Debug)]
-enum PathSource<'a> {
-    // Type paths `Path`.
-    Type,
-    // Trait paths in bounds or impls.
-    Trait(AliasPossibility),
-    // Expression paths `path`, with optional parent context.
-    Expr(Option<&'a Expr>),
-    // Paths in path patterns `Path`.
-    Pat,
-    // Paths in struct expressions and patterns `Path { .. }`.
-    Struct,
-    // Paths in tuple struct patterns `Path(..)`.
-    TupleStruct,
-    // `m::A::B` in `<T as m::A>::B::C`.
-    TraitItem(Namespace),
-    // Path in `pub(path)`
-    Visibility,
-}
-
-impl<'a> PathSource<'a> {
-    fn namespace(self) -> Namespace {
-        match self {
-            PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
-            PathSource::Visibility => TypeNS,
-            PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
-            PathSource::TraitItem(ns) => ns,
-        }
-    }
-
-    fn global_by_default(self) -> bool {
-        match self {
-            PathSource::Visibility => true,
-            PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
-            PathSource::Struct | PathSource::TupleStruct |
-            PathSource::Trait(_) | PathSource::TraitItem(..) => false,
-        }
-    }
-
-    fn defer_to_typeck(self) -> bool {
-        match self {
-            PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
-            PathSource::Struct | PathSource::TupleStruct => true,
-            PathSource::Trait(_) | PathSource::TraitItem(..) |
-            PathSource::Visibility => false,
-        }
-    }
-
-    fn descr_expected(self) -> &'static str {
-        match self {
-            PathSource::Type => "type",
-            PathSource::Trait(_) => "trait",
-            PathSource::Pat => "unit struct/variant or constant",
-            PathSource::Struct => "struct, variant or union type",
-            PathSource::TupleStruct => "tuple struct/variant",
-            PathSource::Visibility => "module",
-            PathSource::TraitItem(ns) => match ns {
-                TypeNS => "associated type",
-                ValueNS => "method or associated constant",
-                MacroNS => bug!("associated macro"),
-            },
-            PathSource::Expr(parent) => match parent.map(|p| &p.node) {
-                // "function" here means "anything callable" rather than `DefKind::Fn`,
-                // this is not precise but usually more helpful than just "value".
-                Some(&ExprKind::Call(..)) => "function",
-                _ => "value",
-            },
-        }
-    }
-
-    fn is_expected(self, res: Res) -> bool {
-        match self {
-            PathSource::Type => match res {
-                Res::Def(DefKind::Struct, _)
-                | Res::Def(DefKind::Union, _)
-                | Res::Def(DefKind::Enum, _)
-                | Res::Def(DefKind::Trait, _)
-                | Res::Def(DefKind::TraitAlias, _)
-                | Res::Def(DefKind::TyAlias, _)
-                | Res::Def(DefKind::AssocTy, _)
-                | Res::PrimTy(..)
-                | Res::Def(DefKind::TyParam, _)
-                | Res::SelfTy(..)
-                | Res::Def(DefKind::OpaqueTy, _)
-                | Res::Def(DefKind::ForeignTy, _) => true,
-                _ => false,
-            },
-            PathSource::Trait(AliasPossibility::No) => match res {
-                Res::Def(DefKind::Trait, _) => true,
-                _ => false,
-            },
-            PathSource::Trait(AliasPossibility::Maybe) => match res {
-                Res::Def(DefKind::Trait, _) => true,
-                Res::Def(DefKind::TraitAlias, _) => true,
-                _ => false,
-            },
-            PathSource::Expr(..) => match res {
-                Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
-                | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
-                | Res::Def(DefKind::Const, _)
-                | Res::Def(DefKind::Static, _)
-                | Res::Local(..)
-                | Res::Def(DefKind::Fn, _)
-                | Res::Def(DefKind::Method, _)
-                | Res::Def(DefKind::AssocConst, _)
-                | Res::SelfCtor(..)
-                | Res::Def(DefKind::ConstParam, _) => true,
-                _ => false,
-            },
-            PathSource::Pat => match res {
-                Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
-                Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
-                Res::SelfCtor(..) => true,
-                _ => false,
-            },
-            PathSource::TupleStruct => match res {
-                Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
-                _ => false,
-            },
-            PathSource::Struct => match res {
-                Res::Def(DefKind::Struct, _)
-                | Res::Def(DefKind::Union, _)
-                | Res::Def(DefKind::Variant, _)
-                | Res::Def(DefKind::TyAlias, _)
-                | Res::Def(DefKind::AssocTy, _)
-                | Res::SelfTy(..) => true,
-                _ => false,
-            },
-            PathSource::TraitItem(ns) => match res {
-                Res::Def(DefKind::AssocConst, _)
-                | Res::Def(DefKind::Method, _) if ns == ValueNS => true,
-                Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
-                _ => false,
-            },
-            PathSource::Visibility => match res {
-                Res::Def(DefKind::Mod, _) => true,
-                _ => false,
-            },
-        }
-    }
-
-    fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
-        __diagnostic_used!(E0404);
-        __diagnostic_used!(E0405);
-        __diagnostic_used!(E0412);
-        __diagnostic_used!(E0422);
-        __diagnostic_used!(E0423);
-        __diagnostic_used!(E0425);
-        __diagnostic_used!(E0531);
-        __diagnostic_used!(E0532);
-        __diagnostic_used!(E0573);
-        __diagnostic_used!(E0574);
-        __diagnostic_used!(E0575);
-        __diagnostic_used!(E0576);
-        __diagnostic_used!(E0577);
-        __diagnostic_used!(E0578);
-        match (self, has_unexpected_resolution) {
-            (PathSource::Trait(_), true) => "E0404",
-            (PathSource::Trait(_), false) => "E0405",
-            (PathSource::Type, true) => "E0573",
-            (PathSource::Type, false) => "E0412",
-            (PathSource::Struct, true) => "E0574",
-            (PathSource::Struct, false) => "E0422",
-            (PathSource::Expr(..), true) => "E0423",
-            (PathSource::Expr(..), false) => "E0425",
-            (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
-            (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
-            (PathSource::TraitItem(..), true) => "E0575",
-            (PathSource::TraitItem(..), false) => "E0576",
-            (PathSource::Visibility, true) => "E0577",
-            (PathSource::Visibility, false) => "E0578",
-        }
-    }
-}
-
 // A minimal representation of a path segment. We use this in resolve because
 // we synthesize 'path segments' which don't have the rest of an AST or HIR
 // `PathSegment`.
@@ -801,255 +302,6 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     }
 }
 
-/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
-impl<'a, 'tcx> Visitor<'tcx> for Resolver<'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)]
-enum RibKind<'a> {
-    /// No restriction needs to be applied.
-    NormalRibKind,
-
-    /// We passed through an impl or trait and are now in one of its
-    /// methods or associated types. Allow references to ty params that impl or trait
-    /// binds. Disallow any other upvars (including other ty params that are
-    /// upvars).
-    AssocItemRibKind,
-
-    /// We passed through a function definition. Disallow upvars.
-    /// Permit only those const parameters that are specified in the function's generics.
-    FnItemRibKind,
-
-    /// We passed through an item scope. Disallow upvars.
-    ItemRibKind,
-
-    /// We're in a constant item. Can't refer to dynamic stuff.
-    ConstantItemRibKind,
-
-    /// We passed through a module.
-    ModuleRibKind(Module<'a>),
-
-    /// We passed through a `macro_rules!` statement
-    MacroDefinition(DefId),
-
-    /// All bindings in this rib are type parameters that can't be used
-    /// from the default of a type parameter because they're not declared
-    /// before said type parameter. Also see the `visit_generics` override.
-    ForwardTyParamBanRibKind,
-
-    /// We forbid the use of type parameters as the types of const parameters.
-    TyParamAsConstParamTy,
-}
-
-/// A single local scope.
-///
-/// A rib represents a scope names can live in. Note that these appear in many places, not just
-/// around braces. At any place where the list of accessible names (of the given namespace)
-/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a
-/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
-/// etc.
-///
-/// Different [rib kinds](enum.RibKind) are transparent for different names.
-///
-/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
-/// resolving, the name is looked up from inside out.
-#[derive(Debug)]
-struct Rib<'a, R = Res> {
-    bindings: FxHashMap<Ident, R>,
-    kind: RibKind<'a>,
-}
-
-impl<'a, R> Rib<'a, R> {
-    fn new(kind: RibKind<'a>) -> Rib<'a, R> {
-        Rib {
-            bindings: Default::default(),
-            kind,
-        }
-    }
-}
-
 /// An intermediate resolution result.
 ///
 /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
@@ -1587,28 +839,6 @@ pub struct Resolver<'a> {
     /// All non-determined imports.
     indeterminate_imports: Vec<&'a ImportDirective<'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>,
-
     /// FIXME: Refactor things so that these fields are passed through arguments and not resolver.
     /// We are resolving a last import segment during import validation.
     last_import_segment: bool,
@@ -1655,10 +885,6 @@ pub struct Resolver<'a> {
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
 
-    /// 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)
-    pub unused_labels: FxHashMap<NodeId, Span>,
-
     /// Privacy errors are delayed until the end in order to deduplicate them.
     privacy_errors: Vec<PrivacyError<'a>>,
     /// Ambiguity errors are delayed for deduplication.
@@ -1703,9 +929,6 @@ pub struct Resolver<'a> {
     /// it's not used during normal resolution, only for better error reporting.
     struct_constructors: DefIdMap<(Res, ty::Visibility)>,
 
-    /// Only used for better errors on `fn(): fn()`.
-    current_type_ascription: Vec<Span>,
-
     injected_crate: Option<Module<'a>>,
 
     /// Features enabled for this crate.
@@ -1766,26 +989,12 @@ impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> {
 /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
 /// the resolver is no longer needed as all the relevant information is inline.
 impl<'a> hir::lowering::Resolver for Resolver<'a> {
-    fn resolve_ast_path(
-        &mut self,
-        path: &ast::Path,
-        is_value: bool,
-    ) -> Res {
-        match self.resolve_ast_path_inner(path, is_value) {
-            Ok(r) => r,
-            Err((span, error)) => {
-                resolve_error(self, span, error);
-                Res::Err
-            }
-        }
-    }
-
     fn resolve_str_path(
         &mut self,
         span: Span,
         crate_root: Option<Symbol>,
         components: &[Symbol],
-        is_value: bool
+        ns: Namespace,
     ) -> (ast::Path, Res) {
         let root = if crate_root.is_some() {
             kw::PathRoot
@@ -1804,7 +1013,14 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
             segments,
         };
 
-        let res = self.resolve_ast_path(&path, is_value);
+        let parent_scope = &self.dummy_parent_scope();
+        let res = match self.resolve_ast_path(&path, ns, parent_scope) {
+            Ok(res) => res,
+            Err((span, error)) => {
+                self.report_error(span, error);
+                Res::Err
+            }
+        };
         (path, res)
     }
 
@@ -1832,76 +1048,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.
-        match self.resolve_path_without_parent_scope(&path, Some(namespace), 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,
@@ -1969,18 +1115,6 @@ impl<'a> Resolver<'a> {
             determined_imports: Vec::new(),
             indeterminate_imports: Vec::new(),
 
-            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,
             last_import_segment: false,
             blacklisted_binding: None,
 
@@ -2002,8 +1136,6 @@ impl<'a> Resolver<'a> {
             maybe_unused_trait_imports: Default::default(),
             maybe_unused_extern_crates: Vec::new(),
 
-            unused_labels: FxHashMap::default(),
-
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
             use_injections: Vec::new(),
@@ -2036,7 +1168,6 @@ impl<'a> Resolver<'a> {
             unused_macros: Default::default(),
             proc_macro_stubs: Default::default(),
             special_derives: Default::default(),
-            current_type_ascription: Vec::new(),
             injected_crate: None,
             active_features:
                 features.declared_lib_features.iter().map(|(feat, ..)| *feat)
@@ -2088,13 +1219,11 @@ impl<'a> Resolver<'a> {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
-        ImportResolver { resolver: self }.finalize_imports();
-        self.current_module = self.graph_root;
-        self.finalize_current_module_macro_resolutions();
+        ImportResolver { r: self }.finalize_imports();
 
-        visit::walk_crate(self, krate);
+        self.late_resolve_crate(krate);
 
-        check_unused::check_crate(self, krate);
+        self.check_unused(krate);
         self.report_errors(krate);
         self.crate_loader.postprocess(krate);
     }
@@ -2203,10 +1332,9 @@ impl<'a> Resolver<'a> {
 
         let rust_2015 = ident.span.rust_2015();
         let (ns, is_absolute_path) = match scope_set {
-            ScopeSet::Import(ns) => (ns, false),
+            ScopeSet::All(ns, _) => (ns, false),
             ScopeSet::AbsolutePath(ns) => (ns, true),
             ScopeSet::Macro(_) => (MacroNS, false),
-            ScopeSet::Module => (TypeNS, false),
         };
         let mut scope = match ns {
             _ if is_absolute_path => Scope::CrateRoot,
@@ -2308,8 +1436,10 @@ impl<'a> Resolver<'a> {
     fn resolve_ident_in_lexical_scope(&mut self,
                                       mut ident: Ident,
                                       ns: Namespace,
+                                      parent_scope: &ParentScope<'a>,
                                       record_used_id: Option<NodeId>,
-                                      path_span: Span)
+                                      path_span: Span,
+                                      ribs: &[Rib<'a>])
                                       -> Option<LexicalScopeBinding<'a>> {
         assert!(ns == TypeNS || ns == ValueNS);
         if ident.name == kw::Invalid {
@@ -2331,23 +1461,23 @@ impl<'a> Resolver<'a> {
         // Walk backwards up the ribs in scope.
         let record_used = record_used_id.is_some();
         let mut module = self.graph_root;
-        for i in (0 .. self.ribs[ns].len()).rev() {
-            debug!("walk rib\n{:?}", self.ribs[ns][i].bindings);
+        for i in (0 .. ribs.len()).rev() {
+            debug!("walk rib\n{:?}", ribs[i].bindings);
             // Use the rib kind to determine whether we are resolving parameters
             // (modern hygiene) or local variables (legacy hygiene).
-            let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind {
+            let rib_ident = if let AssocItemRibKind | ItemRibKind = ribs[i].kind {
                 modern_ident
             } else {
                 ident
             };
-            if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() {
+            if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::Res(
-                    self.validate_res_from_ribs(ns, i, res, record_used, path_span),
+                    self.validate_res_from_ribs(i, res, record_used, path_span, ribs),
                 ));
             }
 
-            module = match self.ribs[ns][i].kind {
+            module = match ribs[i].kind {
                 ModuleRibKind(module) => module,
                 MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
                     // If an invocation of this macro created `ident`, give up on `ident`
@@ -2358,10 +1488,12 @@ impl<'a> Resolver<'a> {
                 _ => continue,
             };
 
+
             let item = self.resolve_ident_in_module_unadjusted(
                 ModuleOrUniformRoot::Module(module),
                 ident,
                 ns,
+                parent_scope,
                 record_used,
                 path_span,
             );
@@ -2386,16 +1518,15 @@ impl<'a> Resolver<'a> {
                 self.hygienic_lexical_parent(module, &mut ident.span)
             };
             module = unwrap_or!(opt_module, break);
-            let orig_current_module = self.current_module;
-            self.current_module = module; // Lexical resolutions can never be a privacy error.
+            let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() };
             let result = self.resolve_ident_in_module_unadjusted(
                 ModuleOrUniformRoot::Module(module),
                 ident,
                 ns,
+                adjusted_parent_scope,
                 record_used,
                 path_span,
             );
-            self.current_module = orig_current_module;
 
             match result {
                 Ok(binding) => {
@@ -2433,6 +1564,7 @@ impl<'a> Resolver<'a> {
                     ModuleOrUniformRoot::Module(prelude),
                     ident,
                     ns,
+                    parent_scope,
                     false,
                     path_span,
                 ) {
@@ -2498,7 +1630,7 @@ impl<'a> Resolver<'a> {
         module: ModuleOrUniformRoot<'a>,
         ident: Ident,
         ns: Namespace,
-        parent_scope: Option<&ParentScope<'a>>,
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         path_span: Span
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
@@ -2512,15 +1644,18 @@ impl<'a> Resolver<'a> {
         module: ModuleOrUniformRoot<'a>,
         mut ident: Ident,
         ns: Namespace,
-        parent_scope: Option<&ParentScope<'a>>,
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         path_span: Span
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
-        let orig_current_module = self.current_module;
+        let tmp_parent_scope;
+        let mut adjusted_parent_scope = parent_scope;
         match module {
-            ModuleOrUniformRoot::Module(module) => {
-                if let Some(def) = ident.span.modernize_and_adjust(module.expansion) {
-                    self.current_module = self.macro_def_scope(def);
+            ModuleOrUniformRoot::Module(m) => {
+                if let Some(def) = ident.span.modernize_and_adjust(m.expansion) {
+                    tmp_parent_scope =
+                        ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() };
+                    adjusted_parent_scope = &tmp_parent_scope;
                 }
             }
             ModuleOrUniformRoot::ExternPrelude => {
@@ -2532,9 +1667,8 @@ impl<'a> Resolver<'a> {
             }
         }
         let result = self.resolve_ident_in_module_unadjusted_ext(
-            module, ident, ns, parent_scope, false, record_used, path_span,
+            module, ident, ns, adjusted_parent_scope, false, record_used, path_span,
         );
-        self.current_module = orig_current_module;
         result
     }
 
@@ -2588,1280 +1722,21 @@ impl<'a> Resolver<'a> {
         module
     }
 
-    // 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.
-
-    pub fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
-        where F: FnOnce(&mut Resolver<'_>) -> 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();
-            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 Resolver<'_>)
-    {
-        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 Resolver<'_>)
-    {
-        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 Resolver<'_>)
-    {
-        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 Resolver<'_>)
-    {
-        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 Resolver<'_>) -> 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 Resolver<'_>) -> 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 Resolver<'_>) -> 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 Resolver<'_>, 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_without_parent_scope(
-                        &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 Resolver<'_>)
-    {
-        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 Resolver<'_>)
-    {
-        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.resolve_visibility(&impl_item.vis);
-
-                                    // 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 {
-            if self.resolve_ident_in_module(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                None,
-                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();
-        } 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(),
-            source.global_by_default(),
-            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(ctor_vis) {
-                                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_without_parent_scope(&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,
-        global_by_default: 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, global_by_default, 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 =
-                ParentScope { module: self.current_module, ..self.dummy_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,
-        global_by_default: bool,
-        crate_lint: CrateLint,
-    ) -> Option<PartialRes> {
-        debug!(
-            "resolve_qpath(id={:?}, qself={:?}, path={:?}, \
-             ns={:?}, span={:?}, global_by_default={:?})",
-            id,
-            qself,
-            path,
-            ns,
-            span,
-            global_by_default,
-        );
-
-        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_without_parent_scope(
-            &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 && !global_by_default && result.base_res() != Res::Err &&
-           path[0].ident.name != kw::PathRoot &&
-           path[0].ident.name != kw::DollarCrate {
-            let unqualified_result = {
-                match self.resolve_path_without_parent_scope(
-                    &[*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 resolve_path_without_parent_scope(
+    fn resolve_path(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         path_span: Span,
         crate_lint: CrateLint,
     ) -> PathResult<'a> {
-        // Macro and import paths must have full parent scope available during resolution,
-        // other paths will do okay with parent module alone.
-        assert!(opt_ns != None && opt_ns != Some(MacroNS));
-        let parent_scope = ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
-        self.resolve_path(path, opt_ns, &parent_scope, record_used, path_span, crate_lint)
+        self.resolve_path_with_ribs(
+            path, opt_ns, parent_scope, record_used, path_span, crate_lint, None
+        )
     }
 
-    fn resolve_path(
+    fn resolve_path_with_ribs(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
@@ -3869,11 +1744,11 @@ impl<'a> Resolver<'a> {
         record_used: bool,
         path_span: Span,
         crate_lint: CrateLint,
+        ribs: Option<&PerNS<Vec<Rib<'a>>>>,
     ) -> PathResult<'a> {
         let mut module = None;
         let mut allow_super = true;
         let mut second_binding = None;
-        self.current_module = parent_scope.module;
 
         debug!(
             "resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \
@@ -3910,7 +1785,7 @@ impl<'a> Resolver<'a> {
                 if allow_super && name == kw::Super {
                     let mut ctxt = ident.span.ctxt().modern();
                     let self_module = match i {
-                        0 => Some(self.resolve_self(&mut ctxt, self.current_module)),
+                        0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
                         _ => match module {
                             Some(ModuleOrUniformRoot::Module(module)) => Some(module),
                             _ => None,
@@ -3935,7 +1810,7 @@ impl<'a> Resolver<'a> {
                     if name == kw::SelfLower {
                         let mut ctxt = ident.span.ctxt().modern();
                         module = Some(ModuleOrUniformRoot::Module(
-                            self.resolve_self(&mut ctxt, self.current_module)));
+                            self.resolve_self(&mut ctxt, parent_scope.module)));
                         continue;
                     }
                     if name == kw::PathRoot && ident.span.rust_2018() {
@@ -3980,16 +1855,19 @@ impl<'a> Resolver<'a> {
             }
 
             let binding = if let Some(module) = module {
-                self.resolve_ident_in_module(module, ident, ns, None, record_used, path_span)
-            } else if opt_ns.is_none() || opt_ns == Some(MacroNS) {
-                assert!(ns == TypeNS);
-                let scopes = if opt_ns.is_none() { ScopeSet::Import(ns) } else { ScopeSet::Module };
+                self.resolve_ident_in_module(
+                    module, ident, ns, parent_scope, record_used, path_span
+                )
+            } else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) {
+                let scopes = ScopeSet::All(ns, opt_ns.is_none());
                 self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used,
                                                           record_used, path_span)
             } else {
                 let record_used_id =
                     if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
-                match self.resolve_ident_in_lexical_scope(ident, ns, record_used_id, path_span) {
+                match self.resolve_ident_in_lexical_scope(
+                    ident, ns, parent_scope, record_used_id, path_span, &ribs.unwrap()[ns]
+                ) {
                     // we found a locally-imported or available item/module
                     Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
                     // we found a local variable or type param
@@ -4176,28 +2054,28 @@ impl<'a> Resolver<'a> {
     // Validate a local resolution (from ribs).
     fn validate_res_from_ribs(
         &mut self,
-        ns: Namespace,
         rib_index: usize,
         res: Res,
         record_used: bool,
         span: Span,
+        all_ribs: &[Rib<'a>],
     ) -> Res {
         debug!("validate_res_from_ribs({:?})", res);
-        let ribs = &self.ribs[ns][rib_index + 1..];
+        let ribs = &all_ribs[rib_index + 1..];
 
         // An invalid forward use of a type parameter from a previous default.
-        if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
+        if let ForwardTyParamBanRibKind = all_ribs[rib_index].kind {
             if record_used {
-                resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam);
+                self.report_error(span, ResolutionError::ForwardDeclaredTyParam);
             }
             assert_eq!(res, Res::Err);
             return Res::Err;
         }
 
         // An invalid use of a type parameter as the type of a const parameter.
-        if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind {
+        if let TyParamAsConstParamTy = all_ribs[rib_index].kind {
             if record_used {
-                resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam);
+                self.report_error(span, ResolutionError::ConstParamDependentOnTypeParam);
             }
             assert_eq!(res, Res::Err);
             return Res::Err;
@@ -4229,14 +2107,14 @@ impl<'a> Resolver<'a> {
                         ConstantItemRibKind => {
                             // Still doesn't deal with upvars
                             if record_used {
-                                resolve_error(self, span, AttemptToUseNonConstantValueInConstant);
+                                self.report_error(span, AttemptToUseNonConstantValueInConstant);
                             }
                             return Res::Err;
                         }
                     }
                 }
                 if let Some(res_err) = res_err {
-                     resolve_error(self, span, res_err);
+                     self.report_error(span, res_err);
                      return Res::Err;
                 }
             }
@@ -4251,10 +2129,8 @@ impl<'a> Resolver<'a> {
                         ItemRibKind | FnItemRibKind => {
                             // This was an attempt to use a type parameter outside its scope.
                             if record_used {
-                                resolve_error(
-                                    self,
-                                    span,
-                                    ResolutionError::GenericParamsFromOuterFunction(res),
+                                self.report_error(
+                                    span, ResolutionError::GenericParamsFromOuterFunction(res)
                                 );
                             }
                             return Res::Err;
@@ -4274,10 +2150,8 @@ impl<'a> Resolver<'a> {
                     if let ItemRibKind | FnItemRibKind = rib.kind {
                         // This was an attempt to use a const parameter outside its scope.
                         if record_used {
-                            resolve_error(
-                                self,
-                                span,
-                                ResolutionError::GenericParamsFromOuterFunction(res),
+                            self.report_error(
+                                span, ResolutionError::GenericParamsFromOuterFunction(res)
                             );
                         }
                         return Res::Err;
@@ -4289,299 +2163,6 @@ impl<'a> Resolver<'a> {
         res
     }
 
-    fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
-        where F: FnOnce(&mut Resolver<'_>)
-    {
-        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 {
-            if self.resolve_ident_in_module(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                None,
-                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
-                }
-                if self.resolve_ident_in_module_unadjusted(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    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
-    }
-
     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) {
@@ -4589,71 +2170,6 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
-        match vis.node {
-            ast::VisibilityKind::Public => ty::Visibility::Public,
-            ast::VisibilityKind::Crate(..) => {
-                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
-            }
-            ast::VisibilityKind::Inherited => {
-                ty::Visibility::Restricted(self.current_module.normal_ancestor_id)
-            }
-            ast::VisibilityKind::Restricted { ref path, id, .. } => {
-                // For visibilities we are not ready to provide correct implementation of "uniform
-                // paths" right now, so on 2018 edition we only allow module-relative paths for now.
-                // On 2015 edition visibilities are resolved as crate-relative by default,
-                // so we are prepending a root segment if necessary.
-                let ident = path.segments.get(0).expect("empty path in visibility").ident;
-                let crate_root = if ident.is_path_segment_keyword() {
-                    None
-                } else if ident.span.rust_2018() {
-                    let msg = "relative paths are not supported in visibilities on 2018 edition";
-                    self.session.struct_span_err(ident.span, msg)
-                        .span_suggestion(
-                            path.span,
-                            "try",
-                            format!("crate::{}", path),
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
-                    return ty::Visibility::Public;
-                } else {
-                    let ctxt = ident.span.ctxt();
-                    Some(Segment::from_ident(Ident::new(
-                        kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
-                    )))
-                };
-
-                let segments = crate_root.into_iter()
-                    .chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
-                let res = self.smart_resolve_path_fragment(
-                    id,
-                    None,
-                    &segments,
-                    path.span,
-                    PathSource::Visibility,
-                    CrateLint::SimplePath(id),
-                ).base_res();
-                if res == Res::Err {
-                    ty::Visibility::Public
-                } else {
-                    let vis = ty::Visibility::Restricted(res.def_id());
-                    if self.is_accessible(vis) {
-                        vis
-                    } else {
-                        self.session.span_err(path.span, "visibilities can only be restricted \
-                                                          to ancestor modules");
-                        ty::Visibility::Public
-                    }
-                }
-            }
-        }
-    }
-
-    fn is_accessible(&self, vis: ty::Visibility) -> bool {
-        vis.is_accessible_from(self.current_module.normal_ancestor_id, self)
-    }
-
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
         vis.is_accessible_from(module.normal_ancestor_id, self)
     }
@@ -5111,14 +2627,79 @@ 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.
+    // FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
+    pub fn resolve_str_path_error(
+        &mut self, span: Span, path_str: &str, ns: Namespace, module_id: NodeId
+    ) -> 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 module = self.block_map.get(&module_id).copied().unwrap_or_else(|| {
+            let def_id = self.definitions.local_def_id(module_id);
+            self.module_map.get(&def_id).copied().unwrap_or(self.graph_root)
+        });
+        let parent_scope = &ParentScope { module, ..self.dummy_parent_scope() };
+        let res = self.resolve_ast_path(&path, ns, parent_scope).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
+    // Resolve a path passed from rustdoc or HIR lowering.
+    fn resolve_ast_path(
+        &mut self,
+        path: &ast::Path,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+    ) -> Result<Res, (Span, ResolutionError<'a>)> {
+        match self.resolve_path(
+            &Segment::from_path(path), Some(ns), parent_scope, true, path.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((path.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 {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 1f534bc41fe..5af71a0170a 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1,18 +1,16 @@
 use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
 use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
 use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
-use crate::{resolve_error, KNOWN_TOOLS};
-use crate::ModuleOrUniformRoot;
+use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
 use crate::Namespace::*;
-use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
+use crate::build_reduced_graph::BuildReducedGraphVisitor;
 use crate::resolve_imports::ImportResolver;
-use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc::hir::map::DefCollector;
 use rustc::middle::stability;
 use rustc::{ty, lint, span_bug};
-use syntax::ast::{self, Ident, ItemKind};
-use syntax::attr::{self, StabilityLevel};
+use syntax::ast::{self, Ident};
+use syntax::attr::StabilityLevel;
 use syntax::edition::Edition;
 use syntax::ext::base::{self, Indeterminate, SpecialDerives};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
@@ -116,21 +114,6 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
     }
 }
 
-fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
-    if attr::contains_name(&item.attrs, sym::proc_macro) {
-        return Some((MacroKind::Bang, item.ident, item.span));
-    } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
-        return Some((MacroKind::Attr, item.ident, item.span));
-    } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
-        if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
-            if let Some(ident) = nested_meta.ident() {
-                return Some((MacroKind::Derive, ident, ident.span));
-            }
-        }
-    }
-    None
-}
-
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -166,21 +149,24 @@ impl<'a> base::Resolver for Resolver<'a> {
         fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expn_id));
 
         let invocation = self.invocations[&expn_id];
-        self.current_module = invocation.module;
-        self.current_module.unresolved_invocations.borrow_mut().remove(&expn_id);
-        self.current_module.unresolved_invocations.borrow_mut().extend(derives);
+        invocation.module.unresolved_invocations.borrow_mut().remove(&expn_id);
+        invocation.module.unresolved_invocations.borrow_mut().extend(derives);
         let parent_def = self.definitions.invocation_parent(expn_id);
         for &derive_invoc_id in derives {
             self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
         }
         self.invocations.extend(derives.iter().map(|&derive| (derive, invocation)));
         let mut visitor = BuildReducedGraphVisitor {
-            resolver: self,
-            current_legacy_scope: invocation.parent_legacy_scope,
-            expansion: expn_id,
+            r: self,
+            parent_scope: ParentScope {
+                module: invocation.module,
+                expansion: expn_id,
+                legacy: invocation.parent_legacy_scope,
+                derives: Vec::new(),
+            },
         };
         fragment.visit_with(&mut visitor);
-        invocation.output_legacy_scope.set(Some(visitor.current_legacy_scope));
+        invocation.output_legacy_scope.set(Some(visitor.parent_scope.legacy));
     }
 
     fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
@@ -191,7 +177,7 @@ impl<'a> base::Resolver for Resolver<'a> {
     }
 
     fn resolve_imports(&mut self) {
-        ImportResolver { resolver: self }.resolve_imports()
+        ImportResolver { r: self }.resolve_imports()
     }
 
     fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool)
@@ -210,10 +196,10 @@ impl<'a> base::Resolver for Resolver<'a> {
                 // will automatically knows about itself.
                 let mut result = Ok(None);
                 if derives.len() > 1 {
-                    let parent_scope = self.invoc_parent_scope(invoc_id, Vec::new());
+                    let parent_scope = &self.invoc_parent_scope(invoc_id, Vec::new());
                     for path in derives {
                         match self.resolve_macro_path(path, Some(MacroKind::Derive),
-                                                      &parent_scope, true, force) {
+                                                      parent_scope, true, force) {
                             Ok((Some(ref ext), _)) if ext.is_derive_copy => {
                                 self.add_derives(invoc.expansion_data.id, SpecialDerives::COPY);
                                 return Ok(None);
@@ -227,8 +213,8 @@ impl<'a> base::Resolver for Resolver<'a> {
             }
         };
 
-        let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
-        let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, force)?;
+        let parent_scope = &self.invoc_parent_scope(invoc_id, derives_in_scope);
+        let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;
 
         let span = invoc.span();
         invoc.expansion_data.id.set_expn_info(ext.expn_info(span, fast_print_path(path)));
@@ -388,8 +374,7 @@ impl<'a> Resolver<'a> {
             self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
             res
         } else {
-            // Macro without a specific kind restriction is equvalent to a macro import.
-            let scope_set = kind.map_or(ScopeSet::Import(MacroNS), ScopeSet::Macro);
+            let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro);
             let binding = self.early_resolve_ident_in_lexical_scope(
                 path[0].ident, scope_set, parent_scope, false, force, path_span
             );
@@ -444,10 +429,9 @@ impl<'a> Resolver<'a> {
         }
 
         let (ns, macro_kind, is_import) = match scope_set {
-            ScopeSet::Import(ns) => (ns, None, true),
+            ScopeSet::All(ns, is_import) => (ns, None, is_import),
             ScopeSet::AbsolutePath(ns) => (ns, None, false),
             ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
-            ScopeSet::Module => (TypeNS, None, false),
         };
 
         // This is *the* result, resolution from the scope closest to the resolved identifier.
@@ -471,9 +455,9 @@ impl<'a> Resolver<'a> {
                 Scope::DeriveHelpers => {
                     let mut result = Err(Determinacy::Determined);
                     for derive in &parent_scope.derives {
-                        let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
+                        let parent_scope = &ParentScope { derives: Vec::new(), ..*parent_scope };
                         match this.resolve_macro_path(derive, Some(MacroKind::Derive),
-                                                      &parent_scope, true, force) {
+                                                      parent_scope, true, force) {
                             Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
                                 let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
                                                ty::Visibility::Public, derive.span, ExpnId::root())
@@ -502,7 +486,7 @@ impl<'a> Resolver<'a> {
                         ModuleOrUniformRoot::Module(root_module),
                         ident,
                         ns,
-                        None,
+                        parent_scope,
                         record_used,
                         path_span,
                     );
@@ -516,17 +500,16 @@ impl<'a> Resolver<'a> {
                     }
                 }
                 Scope::Module(module) => {
-                    let orig_current_module = mem::replace(&mut this.current_module, module);
+                    let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() };
                     let binding = this.resolve_ident_in_module_unadjusted_ext(
                         ModuleOrUniformRoot::Module(module),
                         ident,
                         ns,
-                        None,
+                        adjusted_parent_scope,
                         true,
                         record_used,
                         path_span,
                     );
-                    this.current_module = orig_current_module;
                     match binding {
                         Ok(binding) => {
                             let misc_flags = if ptr::eq(module, this.graph_root) {
@@ -588,6 +571,7 @@ impl<'a> Resolver<'a> {
                             ModuleOrUniformRoot::Module(prelude),
                             ident,
                             ns,
+                            parent_scope,
                             false,
                             path_span,
                         ) {
@@ -710,9 +694,7 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    pub fn finalize_current_module_macro_resolutions(&mut self) {
-        let module = self.current_module;
-
+    pub fn finalize_current_module_macro_resolutions(&mut self, module: Module<'a>) {
         let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind,
                                  initial_res: Option<Res>, res: Res| {
             if let Some(initial_res) = initial_res {
@@ -753,8 +735,9 @@ impl<'a> Resolver<'a> {
         for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
             // FIXME: Path resolution will ICE if segment IDs present.
             for seg in &mut path { seg.id = None; }
-            match self.resolve_path(&path, Some(MacroNS), &parent_scope,
-                                    true, path_span, CrateLint::No) {
+            match self.resolve_path(
+                &path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No
+            ) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                     let res = path_res.base_res();
                     check_consistency(self, &path, path_span, kind, initial_res, res);
@@ -766,7 +749,7 @@ impl<'a> Resolver<'a> {
                         (path_span, format!("partially resolved path in {} {}",
                                             kind.article(), kind.descr()))
                     };
-                    resolve_error(self, span, ResolutionError::FailedToResolve {
+                    self.report_error(span, ResolutionError::FailedToResolve {
                         label,
                         suggestion: None
                     });
@@ -886,62 +869,4 @@ impl<'a> Resolver<'a> {
 
         Lrc::new(result)
     }
-
-    pub fn define_macro(&mut self,
-                        item: &ast::Item,
-                        expansion: ExpnId,
-                        current_legacy_scope: &mut LegacyScope<'a>) {
-        let (ext, ident, span, is_legacy) = match &item.node {
-            ItemKind::MacroDef(def) => {
-                let ext = self.compile_macro(item, self.session.edition());
-                (ext, item.ident, item.span, def.legacy)
-            }
-            ItemKind::Fn(..) => match proc_macro_stub(item) {
-                Some((macro_kind, ident, span)) => {
-                    self.proc_macro_stubs.insert(item.id);
-                    (self.dummy_ext(macro_kind), ident, span, false)
-                }
-                None => return,
-            }
-            _ => unreachable!(),
-        };
-
-        let def_id = self.definitions.local_def_id(item.id);
-        let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
-        self.macro_map.insert(def_id, ext);
-        self.local_macro_def_scopes.insert(item.id, self.current_module);
-
-        if is_legacy {
-            let ident = ident.modern();
-            self.macro_names.insert(ident);
-            let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
-            let vis = if is_macro_export {
-                ty::Visibility::Public
-            } else {
-                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
-            };
-            let binding = (res, vis, span, expansion).to_name_binding(self.arenas);
-            self.set_binding_parent_module(binding, self.current_module);
-            let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding {
-                parent_legacy_scope: *current_legacy_scope, binding, ident
-            });
-            *current_legacy_scope = LegacyScope::Binding(legacy_binding);
-            self.all_macros.insert(ident.name, res);
-            if is_macro_export {
-                let module = self.graph_root;
-                self.define(module, ident, MacroNS,
-                            (res, vis, span, expansion, IsMacroExport));
-            } else {
-                self.check_reserved_macro_name(ident, res);
-                self.unused_macros.insert(item.id, span);
-            }
-        } else {
-            let module = self.current_module;
-            let vis = self.resolve_visibility(&item.vis);
-            if vis != ty::Visibility::Public {
-                self.unused_macros.insert(item.id, span);
-            }
-            self.define(module, ident, MacroNS, (res, vis, span, expansion));
-        }
-    }
 }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 59438883d60..00e89f0fdae 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -5,9 +5,8 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
 use crate::Determinacy::{self, *};
 use crate::Namespace::{self, TypeNS, MacroNS};
 use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use crate::{Resolver, Segment};
+use crate::{Resolver, ResolutionError, Segment};
 use crate::{names_to_string, module_to_string};
-use crate::{resolve_error, ResolutionError};
 use crate::ModuleKind;
 use crate::diagnostics::Suggestion;
 
@@ -27,7 +26,7 @@ use rustc::session::DiagnosticMessageId;
 use rustc::util::nodemap::FxHashSet;
 use rustc::{bug, span_bug};
 
-use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
+use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
 use syntax::ext::hygiene::ExpnId;
 use syntax::symbol::kw;
 use syntax::util::lev_distance::find_best_match_for_name;
@@ -153,10 +152,14 @@ impl<'a> NameResolution<'a> {
                self.single_imports.is_empty() { Some(binding) } else { None }
         })
     }
+
+    crate fn add_single_import(&mut self, directive: &'a ImportDirective<'a>) {
+        self.single_imports.insert(PtrKey(directive));
+    }
 }
 
 impl<'a> Resolver<'a> {
-    fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
+    crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
                   -> &'a RefCell<NameResolution<'a>> {
         *module.resolutions.borrow_mut().entry((ident.modern(), ns))
                .or_insert_with(|| self.arenas.alloc_name_resolution())
@@ -167,11 +170,12 @@ impl<'a> Resolver<'a> {
         module: ModuleOrUniformRoot<'a>,
         ident: Ident,
         ns: Namespace,
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         path_span: Span,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
-            module, ident, ns, None, false, record_used, path_span
+            module, ident, ns, parent_scope, false, record_used, path_span
         ).map_err(|(determinacy, _)| determinacy)
     }
 
@@ -182,7 +186,7 @@ impl<'a> Resolver<'a> {
         module: ModuleOrUniformRoot<'a>,
         ident: Ident,
         ns: Namespace,
-        parent_scope: Option<&ParentScope<'a>>,
+        parent_scope: &ParentScope<'a>,
         restricted_shadowing: bool,
         record_used: bool,
         path_span: Span,
@@ -191,9 +195,8 @@ impl<'a> Resolver<'a> {
             ModuleOrUniformRoot::Module(module) => module,
             ModuleOrUniformRoot::CrateRootAndExternPrelude => {
                 assert!(!restricted_shadowing);
-                let parent_scope = self.dummy_parent_scope();
                 let binding = self.early_resolve_ident_in_lexical_scope(
-                    ident, ScopeSet::AbsolutePath(ns), &parent_scope,
+                    ident, ScopeSet::AbsolutePath(ns), parent_scope,
                     record_used, record_used, path_span,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
@@ -213,9 +216,6 @@ impl<'a> Resolver<'a> {
             }
             ModuleOrUniformRoot::CurrentScope => {
                 assert!(!restricted_shadowing);
-                let parent_scope =
-                    parent_scope.expect("no parent scope for a single-segment import");
-
                 if ns == TypeNS {
                     if ident.name == kw::Crate ||
                         ident.name == kw::DollarCrate {
@@ -232,8 +232,9 @@ impl<'a> Resolver<'a> {
                     }
                 }
 
+                let scopes = ScopeSet::All(ns, true);
                 let binding = self.early_resolve_ident_in_lexical_scope(
-                    ident, ScopeSet::Import(ns), parent_scope, record_used, record_used, path_span
+                    ident, scopes, parent_scope, record_used, record_used, path_span
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -261,7 +262,8 @@ impl<'a> Resolver<'a> {
             }
             // `extern crate` are always usable for backwards compatibility, see issue #37020,
             // remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
-            let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
+            let usable = this.is_accessible_from(binding.vis, parent_scope.module) ||
+                         binding.is_extern_crate();
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
         };
 
@@ -299,7 +301,7 @@ impl<'a> Resolver<'a> {
                         }
                     }
 
-                    if !self.is_accessible(binding.vis) &&
+                    if !self.is_accessible_from(binding.vis, parent_scope.module) &&
                        // Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
                        !(self.last_import_segment && binding.is_extern_crate()) {
                         self.privacy_errors.push(PrivacyError(path_span, ident, binding));
@@ -322,7 +324,7 @@ impl<'a> Resolver<'a> {
         // Check if one of single imports can still define the name,
         // if it can then our result is not determined and can be invalidated.
         for single_import in &resolution.single_imports {
-            if !self.is_accessible(single_import.vis.get()) {
+            if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
                 continue;
             }
             let module = unwrap_or!(single_import.imported_module.get(),
@@ -331,7 +333,7 @@ impl<'a> Resolver<'a> {
                 SingleImport { source, .. } => source,
                 _ => unreachable!(),
             };
-            match self.resolve_ident_in_module(module, ident, ns, Some(&single_import.parent_scope),
+            match self.resolve_ident_in_module(module, ident, ns, &single_import.parent_scope,
                                                false, path_span) {
                 Err(Determined) => continue,
                 Ok(binding) if !self.is_accessible_from(
@@ -379,7 +381,7 @@ impl<'a> Resolver<'a> {
         // Check if one of glob imports can still define the name,
         // if it can then our "no resolution" result is not determined and can be invalidated.
         for glob_import in module.globs.borrow().iter() {
-            if !self.is_accessible(glob_import.vis.get()) {
+            if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) {
                 continue
             }
             let module = match glob_import.imported_module.get() {
@@ -387,9 +389,14 @@ impl<'a> Resolver<'a> {
                 Some(_) => continue,
                 None => return Err((Undetermined, Weak::Yes)),
             };
-            let (orig_current_module, mut ident) = (self.current_module, ident.modern());
+            let tmp_parent_scope;
+            let (mut adjusted_parent_scope, mut ident) = (parent_scope, ident.modern());
             match ident.span.glob_adjust(module.expansion, glob_import.span) {
-                Some(Some(def)) => self.current_module = self.macro_def_scope(def),
+                Some(Some(def)) => {
+                    tmp_parent_scope =
+                        ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() };
+                    adjusted_parent_scope = &tmp_parent_scope;
+                }
                 Some(None) => {}
                 None => continue,
             };
@@ -397,10 +404,10 @@ impl<'a> Resolver<'a> {
                 ModuleOrUniformRoot::Module(module),
                 ident,
                 ns,
+                adjusted_parent_scope,
                 false,
                 path_span,
             );
-            self.current_module = orig_current_module;
 
             match result {
                 Err(Determined) => continue,
@@ -415,52 +422,6 @@ impl<'a> Resolver<'a> {
         Err((Determined, Weak::No))
     }
 
-    // Add an import directive to the current module.
-    pub fn add_import_directive(&mut self,
-                                module_path: Vec<Segment>,
-                                subclass: ImportDirectiveSubclass<'a>,
-                                span: Span,
-                                id: NodeId,
-                                item: &ast::Item,
-                                root_span: Span,
-                                root_id: NodeId,
-                                vis: ty::Visibility,
-                                parent_scope: ParentScope<'a>) {
-        let current_module = parent_scope.module;
-        let directive = self.arenas.alloc_import_directive(ImportDirective {
-            parent_scope,
-            module_path,
-            imported_module: Cell::new(None),
-            subclass,
-            span,
-            id,
-            use_span: item.span,
-            use_span_with_attributes: item.span_with_attributes(),
-            has_attributes: !item.attrs.is_empty(),
-            root_span,
-            root_id,
-            vis: Cell::new(vis),
-            used: Cell::new(false),
-        });
-
-        debug!("add_import_directive({:?})", directive);
-
-        self.indeterminate_imports.push(directive);
-        match directive.subclass {
-            SingleImport { target, type_ns_only, .. } => {
-                self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-                    let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
-                    resolution.single_imports.insert(PtrKey(directive));
-                });
-            }
-            // We don't add prelude imports to the globs since they only affect lexical scopes,
-            // which are not relevant to import resolution.
-            GlobImport { is_prelude: true, .. } => {}
-            GlobImport { .. } => current_module.globs.borrow_mut().push(directive),
-            _ => unreachable!(),
-        }
-    }
-
     // Given a binding and an import directive that resolves to it,
     // return the corresponding binding defined by the import directive.
     crate fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
@@ -635,25 +596,12 @@ struct UnresolvedImportError {
 }
 
 pub struct ImportResolver<'a, 'b> {
-    pub resolver: &'a mut Resolver<'b>,
-}
-
-impl<'a, 'b> std::ops::Deref for ImportResolver<'a, 'b> {
-    type Target = Resolver<'b>;
-    fn deref(&self) -> &Resolver<'b> {
-        self.resolver
-    }
-}
-
-impl<'a, 'b> std::ops::DerefMut for ImportResolver<'a, 'b> {
-    fn deref_mut(&mut self) -> &mut Resolver<'b> {
-        self.resolver
-    }
+    pub r: &'a mut Resolver<'b>,
 }
 
 impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
     fn parent(self, id: DefId) -> Option<DefId> {
-        self.resolver.parent(id)
+        self.r.parent(id)
     }
 }
 
@@ -669,20 +617,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     /// Resolves all imports for the crate. This method performs the fixed-
     /// point iteration.
     pub fn resolve_imports(&mut self) {
-        let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
-        while self.indeterminate_imports.len() < prev_num_indeterminates {
-            prev_num_indeterminates = self.indeterminate_imports.len();
-            for import in mem::take(&mut self.indeterminate_imports) {
+        let mut prev_num_indeterminates = self.r.indeterminate_imports.len() + 1;
+        while self.r.indeterminate_imports.len() < prev_num_indeterminates {
+            prev_num_indeterminates = self.r.indeterminate_imports.len();
+            for import in mem::take(&mut self.r.indeterminate_imports) {
                 match self.resolve_import(&import) {
-                    true => self.determined_imports.push(import),
-                    false => self.indeterminate_imports.push(import),
+                    true => self.r.determined_imports.push(import),
+                    false => self.r.indeterminate_imports.push(import),
                 }
             }
         }
     }
 
     pub fn finalize_imports(&mut self) {
-        for module in self.arenas.local_modules().iter() {
+        for module in self.r.arenas.local_modules().iter() {
             self.finalize_resolutions_in(module);
         }
 
@@ -690,8 +638,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         let mut seen_spans = FxHashSet::default();
         let mut errors = vec![];
         let mut prev_root_id: NodeId = NodeId::from_u32(0);
-        for i in 0 .. self.determined_imports.len() {
-            let import = self.determined_imports[i];
+        for i in 0 .. self.r.determined_imports.len() {
+            let import = self.r.determined_imports[i];
             if let Some(err) = self.finalize_import(import) {
                 has_errors = true;
 
@@ -706,7 +654,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
                 // If the error is a single failed import then create a "fake" import
                 // resolution for it so that later resolve stages won't complain.
-                self.import_dummy_binding(import);
+                self.r.import_dummy_binding(import);
                 if prev_root_id.as_u32() != 0
                         && prev_root_id.as_u32() != import.root_id.as_u32()
                         && !errors.is_empty() {
@@ -735,7 +683,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         // Report unresolved imports only if no hard error was already reported
         // to avoid generating multiple errors on the same import.
         if !has_errors {
-            for import in &self.indeterminate_imports {
+            for import in &self.r.indeterminate_imports {
                 self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span)));
                 break;
             }
@@ -774,7 +722,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             (span, msg)
         };
 
-        let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
+        let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
 
         if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() {
             for message in note {
@@ -798,11 +746,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     /// Attempts to resolve the given import, returning true if its resolution is determined.
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
-        debug!("(resolving import for module) resolving import `{}::...` in `{}`",
-               Segment::names_to_string(&directive.module_path),
-               module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
-
-        self.current_module = directive.parent_scope.module;
+        debug!(
+            "(resolving import for module) resolving import `{}::...` in `{}`",
+            Segment::names_to_string(&directive.module_path),
+            module_to_string(directive.parent_scope.module).unwrap_or_else(|| "???".to_string()),
+        );
 
         let module = if let Some(module) = directive.imported_module.get() {
             module
@@ -810,7 +758,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             // For better failure detection, pretend that the import will
             // not define any names while resolving its module path.
             let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
-            let path_res = self.resolve_path(
+            let path_res = self.r.resolve_path(
                 &directive.module_path,
                 None,
                 &directive.parent_scope,
@@ -841,13 +789,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         };
 
         let mut indeterminate = false;
-        self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+        self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
             if let Err(Undetermined) = source_bindings[ns].get() {
                 // For better failure detection, pretend that the import will
                 // not define any names while resolving its module path.
                 let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
                 let binding = this.resolve_ident_in_module(
-                    module, source, ns, Some(&directive.parent_scope), false, directive.span
+                    module, source, ns, &directive.parent_scope, false, directive.span
                 );
                 directive.vis.set(orig_vis);
 
@@ -892,13 +840,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         &mut self,
         directive: &'b ImportDirective<'b>
     ) -> Option<UnresolvedImportError> {
-        self.current_module = directive.parent_scope.module;
-
         let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
-        let prev_ambiguity_errors_len = self.ambiguity_errors.len();
-        let path_res = self.resolve_path(&directive.module_path, None, &directive.parent_scope,
+        let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
+        let path_res = self.r.resolve_path(&directive.module_path, None, &directive.parent_scope,
                                          true, directive.span, directive.crate_lint());
-        let no_ambiguity = self.ambiguity_errors.len() == prev_ambiguity_errors_len;
+        let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
         directive.vis.set(orig_vis);
         let module = match path_res {
             PathResult::Module(module) => {
@@ -908,10 +854,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         span_bug!(directive.span, "inconsistent resolution for an import");
                     }
                 } else {
-                    if self.privacy_errors.is_empty() {
+                    if self.r.privacy_errors.is_empty() {
                         let msg = "cannot determine resolution for the import";
                         let msg_note = "import resolution is stuck, try simplifying other imports";
-                        self.session.struct_span_err(directive.span, msg).note(msg_note).emit();
+                        self.r.session.struct_span_err(directive.span, msg).note(msg_note).emit();
                     }
                 }
 
@@ -920,7 +866,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
                 if no_ambiguity {
                     assert!(directive.imported_module.get().is_none());
-                    resolve_error(self, span, ResolutionError::FailedToResolve {
+                    self.r.report_error(span, ResolutionError::FailedToResolve {
                         label,
                         suggestion,
                     });
@@ -982,7 +928,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = directive.module_path.clone();
                     full_path.push(Segment::from_ident(Ident::invalid()));
-                    self.lint_if_path_starts_with_module(
+                    self.r.lint_if_path_starts_with_module(
                         directive.crate_lint(),
                         &full_path,
                         directive.span,
@@ -1005,7 +951,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                    max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
                    !max_vis.get().is_at_least(directive.vis.get(), &*self) {
                     let msg = "A non-empty glob must import something with the glob's visibility";
-                    self.session.span_err(directive.span, msg);
+                    self.r.session.span_err(directive.span, msg);
                 }
                 return None;
             }
@@ -1013,13 +959,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         };
 
         let mut all_ns_err = true;
-        self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+        self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
             let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
             let orig_blacklisted_binding =
                 mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get());
             let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
             let binding = this.resolve_ident_in_module(
-                module, ident, ns, Some(&directive.parent_scope), true, directive.span
+                module, ident, ns, &directive.parent_scope, true, directive.span
             );
             this.last_import_segment = orig_last_import_segment;
             this.blacklisted_binding = orig_blacklisted_binding;
@@ -1068,9 +1014,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         if all_ns_err {
             let mut all_ns_failed = true;
-            self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+            self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
                 let binding = this.resolve_ident_in_module(
-                    module, ident, ns, Some(&directive.parent_scope), true, directive.span
+                    module, ident, ns, &directive.parent_scope, true, directive.span
                 );
                 if binding.is_ok() {
                     all_ns_failed = false;
@@ -1147,14 +1093,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 })
             } else {
                 // `resolve_ident_in_module` reported a privacy error.
-                self.import_dummy_binding(directive);
+                self.r.import_dummy_binding(directive);
                 None
             }
         }
 
         let mut reexport_error = None;
         let mut any_successful_reexport = false;
-        self.per_ns(|this, ns| {
+        self.r.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
                 let vis = directive.vis.get();
                 if !binding.pseudo_vis().is_at_least(vis, &*this) {
@@ -1173,12 +1119,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                    re-exported (error E0365), consider declaring with \
                                    `pub`",
                                    ident);
-                self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+                self.r.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
                                          directive.id,
                                          directive.span,
                                          &msg);
             } else if ns == TypeNS {
-                struct_span_err!(self.session, directive.span, E0365,
+                struct_span_err!(self.r.session, directive.span, E0365,
                                  "`{}` is private, and cannot be re-exported", ident)
                     .span_label(directive.span, format!("re-export of private `{}`", ident))
                     .note(&format!("consider declaring type or module `{}` with `pub`", ident))
@@ -1187,7 +1133,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 let msg = format!("`{}` is private, and cannot be re-exported", ident);
                 let note_msg =
                     format!("consider marking `{}` as `pub` in the imported module", ident);
-                struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
+                struct_span_err!(self.r.session, directive.span, E0364, "{}", &msg)
                     .span_note(directive.span, &note_msg)
                     .emit();
             }
@@ -1198,7 +1144,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             // 2 segments, so the `resolve_path` above won't trigger it.
             let mut full_path = directive.module_path.clone();
             full_path.push(Segment::from_ident(ident));
-            self.per_ns(|this, ns| {
+            self.r.per_ns(|this, ns| {
                 if let Ok(binding) = source_bindings[ns].get() {
                     this.lint_if_path_starts_with_module(
                         directive.crate_lint(),
@@ -1213,7 +1159,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         // Record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
-        self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
+        self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
             this.import_res_map.entry(directive.id).or_default()[ns] = Some(binding.res());
         });
 
@@ -1260,7 +1206,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             macro_ns: None,
         };
 
-        self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
+        self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
             if binding.res() == Res::Err {
                 return;
             }
@@ -1272,7 +1218,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
             match this.early_resolve_ident_in_lexical_scope(
                 target,
-                ScopeSet::Import(ns),
+                ScopeSet::All(ns, false),
                 &directive.parent_scope,
                 false,
                 false,
@@ -1298,7 +1244,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
             redundant_spans.sort();
             redundant_spans.dedup();
-            self.session.buffer_lint_with_diagnostic(
+            self.r.session.buffer_lint_with_diagnostic(
                 UNUSED_IMPORTS,
                 directive.id,
                 directive.span,
@@ -1312,20 +1258,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         let module = match directive.imported_module.get().unwrap() {
             ModuleOrUniformRoot::Module(module) => module,
             _ => {
-                self.session.span_err(directive.span, "cannot glob-import all possible crates");
+                self.r.session.span_err(directive.span, "cannot glob-import all possible crates");
                 return;
             }
         };
 
-        self.populate_module_if_necessary(module);
+        self.r.populate_module_if_necessary(module);
 
         if module.is_trait() {
-            self.session.span_err(directive.span, "items in traits are not importable.");
+            self.r.session.span_err(directive.span, "items in traits are not importable.");
             return;
         } else if module.def_id() == directive.parent_scope.module.def_id()  {
             return;
         } else if let GlobImport { is_prelude: true, .. } = directive.subclass {
-            self.prelude = Some(module);
+            self.r.prelude = Some(module);
             return;
         }
 
@@ -1339,18 +1285,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         }).collect::<Vec<_>>();
         for ((mut ident, ns), binding) in bindings {
             let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
-                Some(Some(def)) => self.macro_def_scope(def),
-                Some(None) => self.current_module,
+                Some(Some(def)) => self.r.macro_def_scope(def),
+                Some(None) => directive.parent_scope.module,
                 None => continue,
             };
-            if self.is_accessible_from(binding.pseudo_vis(), scope) {
-                let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
+            if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
+                let imported_binding = self.r.import(binding, directive);
+                let _ =
+                    self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding);
             }
         }
 
         // Record the destination of this import
-        self.record_partial_res(directive.id, PartialRes::new(module.res().unwrap()));
+        self.r.record_partial_res(directive.id, PartialRes::new(module.res().unwrap()));
     }
 
     // Miscellaneous post-processing, including recording re-exports,
@@ -1379,7 +1326,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 if res != Res::Err {
                     if let Some(def_id) = res.opt_def_id() {
                         if !def_id.is_local() {
-                            self.cstore.export_macros_untracked(def_id.krate);
+                            self.r.cstore.export_macros_untracked(def_id.krate);
                         }
                     }
                     reexports.push(Export {
@@ -1405,7 +1352,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
                                                 Some(binding.span),
                                                 msg.clone());
-                                let fresh = self.session.one_time_diagnostics
+                                let fresh = self.r.session.one_time_diagnostics
                                     .borrow_mut().insert(error_id);
                                 if !fresh {
                                     continue;
@@ -1414,7 +1361,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                             },
                             ref s @ _ => bug!("unexpected import subclass {:?}", s)
                         };
-                        let mut err = self.session.struct_span_err(binding.span, &msg);
+                        let mut err = self.r.session.struct_span_err(binding.span, &msg);
 
                         let imported_module = match directive.imported_module.get() {
                             Some(ModuleOrUniformRoot::Module(module)) => module,
@@ -1430,8 +1377,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         let enum_span = enum_resolution.borrow()
                             .binding.expect("binding should exist")
                             .span;
-                        let enum_def_span = self.session.source_map().def_span(enum_span);
-                        let enum_def_snippet = self.session.source_map()
+                        let enum_def_span = self.r.session.source_map().def_span(enum_span);
+                        let enum_def_snippet = self.r.session.source_map()
                             .span_to_snippet(enum_def_span).expect("snippet should exist");
                         // potentially need to strip extant `crate`/`pub(path)` for suggestion
                         let after_vis_index = enum_def_snippet.find("enum")
@@ -1439,7 +1386,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         let suggestion = format!("pub {}",
                                                  &enum_def_snippet[after_vis_index..]);
 
-                        self.session
+                        self.r.session
                             .diag_span_suggestion_once(&mut err,
                                                        DiagnosticMessageId::ErrorId(0),
                                                        enum_def_span,
@@ -1452,7 +1399,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         if reexports.len() > 0 {
             if let Some(def_id) = module.def_id() {
-                self.export_map.insert(def_id, reexports);
+                self.r.export_map.insert(def_id, reexports);
             }
         }
     }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 84cfdd790b7..5c9fac7eab4 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -61,15 +61,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     {
         let cx = self.cx;
 
-        // In case we're in a module, try to resolve the relative
-        // path.
-        if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
-            // FIXME: `with_scope` requires the `NodeId` of a module.
-            let node_id = cx.tcx.hir().hir_to_node_id(id);
+        // In case we're in a module, try to resolve the relative path.
+        if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
+            let module_id = cx.tcx.hir().hir_to_node_id(module_id);
             let result = cx.enter_resolver(|resolver| {
-                resolver.with_scope(node_id, |resolver| {
-                    resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS)
-                })
+                resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
             });
             let result = match result {
                 Ok((_, Res::Err)) => Err(()),
@@ -85,6 +81,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     Res::Def(DefKind::AssocTy, _) => false,
                     Res::Def(DefKind::Variant, _) => return handle_variant(cx, res),
                     // Not a trait item; just return what we found.
+                    Res::PrimTy(..) => return Ok((res, Some(path_str.to_owned()))),
                     _ => return Ok((res, None))
                 };
 
@@ -133,11 +130,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     .ok_or(());
             }
 
-            // FIXME: `with_scope` requires the `NodeId` of a module.
-            let node_id = cx.tcx.hir().hir_to_node_id(id);
-            let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| {
-                    resolver.resolve_str_path_error(DUMMY_SP, &path, false)
-            }))?;
+            let (_, ty_res) = cx.enter_resolver(|resolver| {
+                resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
+            })?;
             if let Res::Err = ty_res {
                 return Err(());
             }
diff --git a/src/test/ui/hygiene/privacy-early.rs b/src/test/ui/hygiene/privacy-early.rs
new file mode 100644
index 00000000000..58fc74d65a5
--- /dev/null
+++ b/src/test/ui/hygiene/privacy-early.rs
@@ -0,0 +1,17 @@
+// edition:2018
+
+#![feature(decl_macro)]
+
+mod foo {
+    fn f() {}
+    macro f() {}
+
+    pub macro m() {
+        use f as g; //~ ERROR `f` is private, and cannot be re-exported
+        f!();
+    }
+}
+
+fn main() {
+    foo::m!();
+}
diff --git a/src/test/ui/hygiene/privacy-early.stderr b/src/test/ui/hygiene/privacy-early.stderr
new file mode 100644
index 00000000000..60e50e05fc3
--- /dev/null
+++ b/src/test/ui/hygiene/privacy-early.stderr
@@ -0,0 +1,21 @@
+error[E0364]: `f` is private, and cannot be re-exported
+  --> $DIR/privacy-early.rs:10:13
+   |
+LL |         use f as g;
+   |             ^^^^^^
+...
+LL |     foo::m!();
+   |     ---------- in this macro invocation
+   |
+note: consider marking `f` as `pub` in the imported module
+  --> $DIR/privacy-early.rs:10:13
+   |
+LL |         use f as g;
+   |             ^^^^^^
+...
+LL |     foo::m!();
+   |     ---------- in this macro invocation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0364`.
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
index ae44b371f4f..877940c7403 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
@@ -1,5 +1,5 @@
 // edition:2018
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
diff --git a/src/test/ui/resolve/resolve-bad-visibility.rs b/src/test/ui/resolve/resolve-bad-visibility.rs
index d86c300c93f..7d48bb97b10 100644
--- a/src/test/ui/resolve/resolve-bad-visibility.rs
+++ b/src/test/ui/resolve/resolve-bad-visibility.rs
@@ -4,8 +4,8 @@ trait Tr {}
 pub(in E) struct S; //~ ERROR expected module, found enum `E`
 pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr`
 pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules
-pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root
-pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root
+pub(in nonexistent) struct G; //~ ERROR failed to resolve
+pub(in too_soon) struct H; //~ ERROR failed to resolve
 
 // Visibilities are resolved eagerly without waiting for modules becoming fully populated.
 // Visibilities can only use ancestor modules legally which are always available in time,
diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr
index b8004a48a67..d2fb7c7a9e6 100644
--- a/src/test/ui/resolve/resolve-bad-visibility.stderr
+++ b/src/test/ui/resolve/resolve-bad-visibility.stderr
@@ -1,9 +1,3 @@
-error: visibilities can only be restricted to ancestor modules
-  --> $DIR/resolve-bad-visibility.rs:6:8
-   |
-LL | pub(in std::vec) struct F;
-   |        ^^^^^^^^
-
 error[E0577]: expected module, found enum `E`
   --> $DIR/resolve-bad-visibility.rs:4:8
    |
@@ -16,17 +10,24 @@ error[E0577]: expected module, found trait `Tr`
 LL | pub(in Tr) struct Z;
    |        ^^ not a module
 
-error[E0578]: cannot find module `nonexistent` in the crate root
+error: visibilities can only be restricted to ancestor modules
+  --> $DIR/resolve-bad-visibility.rs:6:8
+   |
+LL | pub(in std::vec) struct F;
+   |        ^^^^^^^^
+
+error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
   --> $DIR/resolve-bad-visibility.rs:7:8
    |
 LL | pub(in nonexistent) struct G;
-   |        ^^^^^^^^^^^ not found in the crate root
+   |        ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
 
-error[E0578]: cannot find module `too_soon` in the crate root
+error[E0433]: failed to resolve: maybe a missing crate `too_soon`?
   --> $DIR/resolve-bad-visibility.rs:8:8
    |
 LL | pub(in too_soon) struct H;
-   |        ^^^^^^^^ not found in the crate root
+   |        ^^^^^^^^ maybe a missing crate `too_soon`?
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/visibility-indeterminate.rs b/src/test/ui/resolve/visibility-indeterminate.rs
new file mode 100644
index 00000000000..595eaf440c9
--- /dev/null
+++ b/src/test/ui/resolve/visibility-indeterminate.rs
@@ -0,0 +1,5 @@
+// edition:2018
+
+foo!(); //~ ERROR cannot find macro `foo!` in this scope
+
+pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility
diff --git a/src/test/ui/resolve/visibility-indeterminate.stderr b/src/test/ui/resolve/visibility-indeterminate.stderr
new file mode 100644
index 00000000000..a259c8090b3
--- /dev/null
+++ b/src/test/ui/resolve/visibility-indeterminate.stderr
@@ -0,0 +1,19 @@
+error[E0578]: cannot determine resolution for the visibility
+  --> $DIR/visibility-indeterminate.rs:5:8
+   |
+LL | pub(in ::bar) struct Baz {}
+   |        ^^^^^
+
+error: cannot find macro `foo!` in this scope
+  --> $DIR/visibility-indeterminate.rs:3:1
+   |
+LL | foo!();
+   | ^^^
+
+error[E0601]: `main` function not found in crate `visibility_indeterminate`
+   |
+   = note: consider adding a `main` function to `$DIR/visibility-indeterminate.rs`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/span/visibility-ty-params.stderr b/src/test/ui/span/visibility-ty-params.stderr
index cdbede3c197..c2f0711b0c8 100644
--- a/src/test/ui/span/visibility-ty-params.stderr
+++ b/src/test/ui/span/visibility-ty-params.stderr
@@ -4,19 +4,17 @@ error: unexpected generic arguments in path
 LL | m!{ S<u8> }
    |     ^^^^^
 
+error[E0577]: expected module, found struct `S`
+  --> $DIR/visibility-ty-params.rs:6:5
+   |
+LL | m!{ S<u8> }
+   |     ^^^^^ not a module
+
 error: unexpected generic arguments in path
   --> $DIR/visibility-ty-params.rs:10:9
    |
 LL |     m!{ m<> }
    |         ^^^
 
-error[E0577]: expected module, found struct `S`
-  --> $DIR/visibility-ty-params.rs:6:5
-   |
-LL | m!{ S<u8> }
-   |     -^^^^
-   |     |
-   |     help: a module with a similar name exists: `m`
-
 error: aborting due to 3 previous errors