about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-09-18 23:41:41 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-10-18 10:42:39 +0300
commitc1e8fc8c97831ac1d167e54c3d7b84305c697b87 (patch)
tree62686138ac301193b06bdcf740d5bd2d84aa7b3e /compiler
parent5e02151318ddd431aea6d58e23948246c1446044 (diff)
downloadrust-c1e8fc8c97831ac1d167e54c3d7b84305c697b87.tar.gz
rust-c1e8fc8c97831ac1d167e54c3d7b84305c697b87.zip
resolve: Use `NameBinding` for local variables and generic parameters
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_resolve/src/late.rs161
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs3
-rw-r--r--compiler/rustc_resolve/src/lib.rs194
3 files changed, 145 insertions, 213 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 95633257965..a52dbe4f540 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -7,7 +7,7 @@
 
 use RibKind::*;
 
-use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
+use crate::{path_names_to_string, BindingError, CrateLint, NameBinding, ToNameBinding};
 use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult};
 use crate::{ResolutionError, Resolver, Segment, UseError};
 
@@ -21,27 +21,22 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::{PrimTy, TraitCandidate};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_session::lint;
+use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
+use tracing::debug;
 
-use rustc_span::source_map::{respan, Spanned};
 use std::collections::{hash_map::Entry, BTreeSet};
 use std::mem::{replace, take};
-use tracing::debug;
 
 mod diagnostics;
 crate mod lifetimes;
 
 type Res = def::Res<NodeId>;
 
-type IdentMap<T> = FxHashMap<Ident, T>;
-
-/// Map from the name in a pattern to its binding mode.
-type BindingMap = IdentMap<BindingInfo>;
-
 #[derive(Copy, Clone, Debug)]
 struct BindingInfo {
     span: Span,
@@ -172,8 +167,8 @@ impl RibKind<'_> {
 /// 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: IdentMap<R>,
+crate struct Rib<'a, R = &'a NameBinding<'a>> {
+    pub bindings: FxHashMap<Ident, R>,
     pub kind: RibKind<'a>,
 }
 
@@ -567,12 +562,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 GenericParamKind::Type { .. } => {
                     forward_ty_ban_rib
                         .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                        .insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding);
                 }
                 GenericParamKind::Const { .. } => {
                     forward_const_ban_rib
                         .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                        .insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding);
                 }
                 GenericParamKind::Lifetime => {}
             }
@@ -589,7 +584,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         // such as in the case of `trait Add<Rhs = Self>`.)
         if self.diagnostic_metadata.current_self_item.is_some() {
             // (`Some` if + only if we are in ADT's generics.)
-            forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
+            forward_ty_ban_rib
+                .bindings
+                .insert(Ident::with_dummy_span(kw::SelfUpper), self.r.dummy_binding);
         }
 
         for param in &generics.params {
@@ -737,15 +734,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         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],
-        )
+    ) -> Option<&'a NameBinding<'a>> {
+        self.r
+            .resolve_ident_in_lexical_scope(
+                ident,
+                ns,
+                &self.parent_scope,
+                record_used_id,
+                path_span,
+                &self.ribs[ns],
+            )
+            .ok()
     }
 
     fn resolve_path(
@@ -903,6 +902,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     fn future_proof_import(&mut self, use_tree: &UseTree) {
+        if !self.should_report_errs() {
+            return;
+        }
+
         let segments = &use_tree.prefix.segments;
         if !segments.is_empty() {
             let ident = segments[0].ident;
@@ -914,31 +917,42 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
                 _ => &[TypeNS],
             };
+
+            let from_ribs = |binding: &NameBinding<'_>| {
+                matches!(
+                    binding.res(),
+                    Res::Local(..)
+                        | Res::SelfTy(..)
+                        | Res::Def(DefKind::TyParam | DefKind::ConstParam, ..)
+                )
+            };
             let report_error = |this: &Self, ns| {
                 let what = if ns == TypeNS { "type parameters" } else { "local variables" };
-                if this.should_report_errs() {
-                    this.r
-                        .session
-                        .span_err(ident.span, &format!("imports cannot refer to {}", what));
-                }
+                let msg = format!("imports cannot refer to {what}");
+                this.r.session.span_err(ident.span, &msg);
             };
 
             for &ns in nss {
-                match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
-                    Some(LexicalScopeBinding::Res(..)) => {
+                if let Some(binding) =
+                    self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span)
+                {
+                    if from_ribs(binding) {
                         report_error(self, ns);
-                    }
-                    Some(LexicalScopeBinding::Item(binding)) => {
+                    } else {
                         let orig_unusable_binding =
                             replace(&mut self.r.unusable_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);
+                        if let Some(binding) = self.resolve_ident_in_lexical_scope(
+                            ident,
+                            ns,
+                            None,
+                            use_tree.prefix.span,
+                        ) {
+                            if from_ribs(binding) {
+                                report_error(self, ns);
+                            }
                         }
                         self.r.unusable_binding = orig_unusable_binding;
                     }
-                    None => {}
                 }
             }
         } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
@@ -1135,8 +1149,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 _ => unreachable!(),
             };
             let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
+            let binding =
+                (res, ty::Visibility::Invisible, param.ident.span, self.parent_scope.expansion)
+                    .to_name_binding(self.r.arenas);
+
             self.r.record_partial_res(param.id, PartialRes::new(res));
-            rib.bindings.insert(ident, res);
+            rib.bindings.insert(ident, binding);
         }
 
         self.ribs[ValueNS].push(function_value_rib);
@@ -1256,10 +1274,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) {
+        let binding = (self_res, ty::Visibility::Invisible, DUMMY_SP, self.parent_scope.expansion)
+            .to_name_binding(self.r.arenas);
         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_dummy_span(kw::SelfUpper), self_res);
+        self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), binding);
         self.ribs[ns].push(self_type_rib);
         f(self);
         self.ribs[ns].pop();
@@ -1470,7 +1490,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     /// 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 {
+    fn binding_mode_map(&mut self, pat: &Pat) -> FxHashMap<Ident, BindingInfo> {
         let mut binding_map = FxHashMap::default();
 
         pat.walk(&mut |pat| {
@@ -1503,7 +1523,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
     /// 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>]) -> Vec<BindingMap> {
+    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<FxHashMap<Ident, BindingInfo>> {
         let mut missing_vars = FxHashMap::default();
         let mut inconsistent_vars = FxHashMap::default();
 
@@ -1645,7 +1665,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
                         .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
                     self.r.record_partial_res(pat.id, PartialRes::new(res));
-                    self.r.record_pat_span(pat.id, pat.span);
                 }
                 PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
                     self.smart_resolve_path(
@@ -1735,18 +1754,24 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         if already_bound_or {
             // `Variant1(a) | Variant2(a)`, ok
             // Reuse definition from the first `a`.
-            self.innermost_rib_bindings(ValueNS)[&ident]
+            self.innermost_rib_bindings(ValueNS)[&ident].res()
         } else {
             let res = Res::Local(pat_id);
             if ident_valid {
                 // A completely fresh binding add to the set if it's valid.
-                self.innermost_rib_bindings(ValueNS).insert(ident, res);
+                let binding =
+                    (res, ty::Visibility::Invisible, ident.span, self.parent_scope.expansion)
+                        .to_name_binding(self.r.arenas);
+                self.innermost_rib_bindings(ValueNS).insert(ident, binding);
             }
             res
         }
     }
 
-    fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap<Res> {
+    fn innermost_rib_bindings(
+        &mut self,
+        ns: Namespace,
+    ) -> &mut FxHashMap<Ident, &'a NameBinding<'a>> {
         &mut self.ribs[ns].last_mut().unwrap().bindings
     }
 
@@ -1763,22 +1788,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         // also be interpreted as a path to e.g. a constant, variant, etc.
         let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
 
-        let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?;
-        let (res, binding) = match ls_binding {
-            LexicalScopeBinding::Item(binding)
-                if is_syntactic_ambiguity && binding.is_ambiguity() =>
-            {
-                // For ambiguous bindings we don't know all their definitions and cannot check
-                // whether they can be shadowed by fresh bindings or not, so force an error.
-                // issues/33118#issuecomment-233962221 (see below) still applies here,
-                // but we have to ignore it for backward compatibility.
-                self.r.record_use(ident, binding, false);
-                return None;
-            }
-            LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
-            LexicalScopeBinding::Res(res) => (res, None),
-        };
+        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?;
+        if is_syntactic_ambiguity && binding.is_ambiguity() {
+            // For ambiguous bindings we don't know all their definitions and cannot check
+            // whether they can be shadowed by fresh bindings or not, so force an error.
+            // issues/33118#issuecomment-233962221 (see below) still applies here,
+            // but we have to ignore it for backward compatibility.
+            self.r.record_use(ident, binding, false);
+            return None;
+        }
 
+        let res = binding.res();
         match res {
             Res::SelfCtor(_) // See #70549.
             | Res::Def(
@@ -1786,9 +1806,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 _,
             ) if is_syntactic_ambiguity => {
                 // Disambiguate in favor of a unit struct/variant or constant pattern.
-                if let Some(binding) = binding {
-                    self.r.record_use(ident, binding, false);
-                }
+                self.r.record_use(ident, binding, false);
                 Some(res)
             }
             Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => {
@@ -1797,7 +1815,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // 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.
-                let binding = binding.expect("no binding for a ctor or static");
                 self.report_error(
                     ident.span,
                     ResolutionError::BindingShadowsSomethingUnacceptable {
@@ -2037,19 +2054,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     fn self_type_is_available(&mut self, span: Span) -> bool {
-        let binding = self.resolve_ident_in_lexical_scope(
-            Ident::with_dummy_span(kw::SelfUpper),
-            TypeNS,
-            None,
-            span,
-        );
-        if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
+        let ident = Ident::with_dummy_span(kw::SelfUpper);
+        self.resolve_ident_in_lexical_scope(ident, TypeNS, None, span)
+            .map_or(false, |binding| binding.res() != Res::Err)
     }
 
     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 }
+        self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span)
+            .map_or(false, |binding| binding.res() != Res::Err)
     }
 
     /// A wrapper around [`Resolver::report_error`].
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1748a9be8e1..506f1549753 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1294,7 +1294,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             // 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 {
+                for (ident, binding) in &rib.bindings {
+                    let res = binding.res();
                     if filter_fn(res) {
                         names.push(TypoSuggestion::typo_from_res(ident.name, res));
                     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9652c483686..0c69a666a7e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -371,26 +371,6 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     }
 }
 
-/// An intermediate resolution result.
-///
-/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
-/// items are visible in their whole block, while `Res`es only from the place they are defined
-/// forward.
-#[derive(Debug)]
-enum LexicalScopeBinding<'a> {
-    Item(&'a NameBinding<'a>),
-    Res(Res),
-}
-
-impl<'a> LexicalScopeBinding<'a> {
-    fn res(self) -> Res {
-        match self {
-            LexicalScopeBinding::Item(binding) => binding.res(),
-            LexicalScopeBinding::Res(res) => res,
-        }
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 enum ModuleOrUniformRoot<'a> {
     /// Regular module.
@@ -916,10 +896,6 @@ pub struct Resolver<'a> {
     /// "self-confirming" import resolutions during import validation.
     unusable_binding: Option<&'a NameBinding<'a>>,
 
-    // Spans for local variables found during pattern resolution.
-    // Used for suggestions during error reporting.
-    pat_span_map: NodeMap<Span>,
-
     /// Resolutions for nodes that have a single resolution.
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -1357,7 +1333,6 @@ impl<'a> Resolver<'a> {
             last_import_segment: false,
             unusable_binding: None,
 
-            pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
@@ -1383,13 +1358,8 @@ impl<'a> Resolver<'a> {
             macro_expanded_macro_export_errors: BTreeSet::new(),
 
             arenas,
-            dummy_binding: arenas.alloc_name_binding(NameBinding {
-                kind: NameBindingKind::Res(Res::Err, false),
-                ambiguity: None,
-                expansion: LocalExpnId::ROOT,
-                span: DUMMY_SP,
-                vis: ty::Visibility::Public,
-            }),
+            dummy_binding: (Res::Err, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
+                .to_name_binding(arenas),
 
             crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
             macro_names: FxHashSet::default(),
@@ -1953,11 +1923,11 @@ impl<'a> Resolver<'a> {
         record_used_id: Option<NodeId>,
         path_span: Span,
         ribs: &[Rib<'a>],
-    ) -> Option<LexicalScopeBinding<'a>> {
+    ) -> Result<&'a NameBinding<'a>, Determinacy> {
         assert!(ns == TypeNS || ns == ValueNS);
         let orig_ident = ident;
         if ident.name == kw::Empty {
-            return Some(LexicalScopeBinding::Res(Res::Err));
+            return Ok(self.dummy_binding);
         }
         let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
             // FIXME(jseyfried) improve `Self` hygiene
@@ -1980,18 +1950,30 @@ impl<'a> Resolver<'a> {
             // Use the rib kind to determine whether we are resolving parameters
             // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
             let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
-            if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
+            if let Some((&original_rib_ident_def, &binding)) =
+                ribs[i].bindings.get_key_value(&rib_ident)
             {
                 // The ident resolves to a type parameter or local variable.
-                return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
+                let res = self.validate_res_from_ribs(
                     i,
                     rib_ident,
-                    *res,
+                    binding.res(),
                     record_used,
                     path_span,
-                    *original_rib_ident_def,
+                    original_rib_ident_def,
                     ribs,
-                )));
+                );
+
+                // We have to create a new binding in case of validation errors,
+                // or in case of const generic hack changing the resolution.
+                return Ok(if res != binding.res() {
+                    self.arenas.alloc_name_binding(NameBinding {
+                        kind: NameBindingKind::Res(res, false),
+                        ..binding.clone()
+                    })
+                } else {
+                    binding
+                });
             }
 
             module = match ribs[i].kind {
@@ -2010,7 +1992,7 @@ impl<'a> Resolver<'a> {
                 _ => break,
             }
 
-            let item = self.resolve_ident_in_module_unadjusted(
+            let binding = self.resolve_ident_in_module_unadjusted(
                 ModuleOrUniformRoot::Module(module),
                 ident,
                 ns,
@@ -2018,9 +2000,9 @@ impl<'a> Resolver<'a> {
                 record_used,
                 path_span,
             );
-            if let Ok(binding) = item {
+            if binding.is_ok() {
                 // The ident resolves to an item.
-                return Some(LexicalScopeBinding::Item(binding));
+                return binding;
             }
         }
         self.early_resolve_ident_in_lexical_scope(
@@ -2031,8 +2013,6 @@ impl<'a> Resolver<'a> {
             record_used,
             path_span,
         )
-        .ok()
-        .map(LexicalScopeBinding::Item)
     }
 
     fn hygienic_lexical_parent(
@@ -2257,16 +2237,6 @@ impl<'a> Resolver<'a> {
 
         for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
-            let record_segment_res = |this: &mut Self, res| {
-                if record_used {
-                    if let Some(id) = id {
-                        if !this.partial_res_map.contains_key(&id) {
-                            assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
-                            this.record_partial_res(id, PartialRes::new(res));
-                        }
-                    }
-                }
-            };
 
             let is_last = i == path.len() - 1;
             let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
@@ -2345,12 +2315,8 @@ impl<'a> Resolver<'a> {
                 };
             }
 
-            enum FindBindingResult<'a> {
-                Binding(Result<&'a NameBinding<'a>, Determinacy>),
-                PathResult(PathResult<'a>),
-            }
             let find_binding_in_ns = |this: &mut Self, ns| {
-                let binding = if let Some(module) = module {
+                if let Some(module) = module {
                     this.resolve_ident_in_module(
                         module,
                         ident,
@@ -2375,44 +2341,34 @@ impl<'a> Resolver<'a> {
                     } else {
                         None
                     };
-                    match this.resolve_ident_in_lexical_scope(
+                    this.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
-                        Some(LexicalScopeBinding::Res(res))
-                            if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) =>
-                        {
-                            record_segment_res(this, res);
-                            return FindBindingResult::PathResult(PathResult::NonModule(
-                                PartialRes::with_unresolved_segments(res, path.len() - 1),
-                            ));
-                        }
-                        _ => Err(Determinacy::determined(record_used)),
-                    }
-                };
-                FindBindingResult::Binding(binding)
-            };
-            let binding = match find_binding_in_ns(self, ns) {
-                FindBindingResult::PathResult(x) => return x,
-                FindBindingResult::Binding(binding) => binding,
+                    )
+                }
             };
-            match binding {
+
+            match find_binding_in_ns(self, ns) {
                 Ok(binding) => {
                     if i == 1 {
                         second_binding = Some(binding);
                     }
                     let res = binding.res();
+                    if record_used {
+                        if let Some(id) = id {
+                            if !self.partial_res_map.contains_key(&id) {
+                                assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+                                self.record_partial_res(id, PartialRes::new(res));
+                            }
+                        }
+                    }
                     let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
                     if let Some(next_module) = binding.module() {
                         module = Some(ModuleOrUniformRoot::Module(next_module));
-                        record_segment_res(self, res);
                     } else if res == Res::ToolMod && i + 1 != path.len() {
                         if binding.is_import() {
                             self.session
@@ -2502,56 +2458,25 @@ impl<'a> Resolver<'a> {
                             .map_or(false, |c| c.is_ascii_uppercase())
                         {
                             // Check whether the name refers to an item in the value namespace.
-                            let suggestion = if ribs.is_some() {
-                                let match_span = match self.resolve_ident_in_lexical_scope(
-                                    ident,
-                                    ValueNS,
-                                    parent_scope,
-                                    None,
-                                    path_span,
-                                    &ribs.unwrap()[ValueNS],
-                                ) {
-                                    // Name matches a local variable. For example:
-                                    // ```
-                                    // fn f() {
-                                    //     let Foo: &str = "";
-                                    //     println!("{}", Foo::Bar); // Name refers to local
-                                    //                               // variable `Foo`.
-                                    // }
-                                    // ```
-                                    Some(LexicalScopeBinding::Res(Res::Local(id))) => {
-                                        Some(*self.pat_span_map.get(&id).unwrap())
-                                    }
-
-                                    // Name matches item from a local name binding
-                                    // created by `use` declaration. For example:
-                                    // ```
-                                    // pub Foo: &str = "";
-                                    //
-                                    // mod submod {
-                                    //     use super::Foo;
-                                    //     println!("{}", Foo::Bar); // Name refers to local
-                                    //                               // binding `Foo`.
-                                    // }
-                                    // ```
-                                    Some(LexicalScopeBinding::Item(name_binding)) => {
-                                        Some(name_binding.span)
-                                    }
-                                    _ => None,
-                                };
-
-                                if let Some(span) = match_span {
-                                    Some((
-                                        vec![(span, String::from(""))],
+                            let suggestion = ribs
+                                .and_then(|ribs| {
+                                    self.resolve_ident_in_lexical_scope(
+                                        ident,
+                                        ValueNS,
+                                        parent_scope,
+                                        None,
+                                        path_span,
+                                        &ribs[ValueNS],
+                                    )
+                                    .ok()
+                                })
+                                .map(|binding| {
+                                    (
+                                        vec![(binding.span, String::from(""))],
                                         format!("`{}` is defined here, but is not a type", ident),
                                         Applicability::MaybeIncorrect,
-                                    ))
-                                } else {
-                                    None
-                                }
-                            } else {
-                                None
-                            };
+                                    )
+                                });
 
                             (format!("use of undeclared type `{}`", ident), suggestion)
                         } else {
@@ -2589,9 +2514,7 @@ impl<'a> Resolver<'a> {
                         let mut msg = format!("could not find `{}` in {}", ident, parent);
                         if ns == TypeNS || ns == ValueNS {
                             let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
-                            if let FindBindingResult::Binding(Ok(binding)) =
-                                find_binding_in_ns(self, ns_to_try)
-                            {
+                            if let Ok(binding) = find_binding_in_ns(self, ns_to_try) {
                                 let mut found = |what| {
                                     msg = format!(
                                         "expected {}, found {} `{}` in {}",
@@ -2933,11 +2856,6 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn record_pat_span(&mut self, node: NodeId, span: Span) {
-        debug!("(recording pat) recording {:?} for {:?}", node, span);
-        self.pat_span_map.insert(node, span);
-    }
-
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod(), self)
     }