diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fbb1a868bde..0a24e00ee4b 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, NameBinding, ToNameBinding}; +use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; @@ -21,22 +21,27 @@ 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, ty}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; 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; +type IdentMap = FxHashMap; + +/// Map from the name in a pattern to its binding mode. +type BindingMap = IdentMap; + #[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, @@ -167,8 +172,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 = &'a NameBinding<'a>> { - pub bindings: FxHashMap, +crate struct Rib<'a, R = Res> { + pub bindings: IdentMap, pub kind: RibKind<'a>, } @@ -562,12 +567,12 @@ fn visit_generics(&mut self, generics: &'ast Generics) { GenericParamKind::Type { .. } => { forward_ty_ban_rib .bindings - .insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding); + .insert(Ident::with_dummy_span(param.ident.name), Res::Err); } GenericParamKind::Const { .. } => { forward_const_ban_rib .bindings - .insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding); + .insert(Ident::with_dummy_span(param.ident.name), Res::Err); } GenericParamKind::Lifetime => {} } @@ -584,9 +589,7 @@ fn visit_generics(&mut self, generics: &'ast Generics) { // such as in the case of `trait Add`.) 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), self.r.dummy_binding); + forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); } for param in &generics.params { @@ -734,17 +737,15 @@ fn resolve_ident_in_lexical_scope( ns: Namespace, record_used_id: Option, path_span: Span, - ) -> 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() + ) -> Option> { + self.r.resolve_ident_in_lexical_scope( + ident, + ns, + &self.parent_scope, + record_used_id, + path_span, + &self.ribs[ns], + ) } fn resolve_path( @@ -902,10 +903,6 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { } 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; @@ -917,42 +914,31 @@ fn future_proof_import(&mut self, use_tree: &UseTree) { 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" }; - let msg = format!("imports cannot refer to {what}"); - this.r.session.span_err(ident.span, &msg); + if this.should_report_errs() { + this.r + .session + .span_err(ident.span, &format!("imports cannot refer to {}", what)); + } }; for &ns in nss { - if let Some(binding) = - self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) - { - if from_ribs(binding) { + match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { + Some(LexicalScopeBinding::Res(..)) => { report_error(self, ns); - } else { + } + Some(LexicalScopeBinding::Item(binding)) => { let orig_unusable_binding = replace(&mut self.r.unusable_binding, Some(binding)); - 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); - } + if let Some(LexicalScopeBinding::Res(..)) = self + .resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) + { + report_error(self, ns); } self.r.unusable_binding = orig_unusable_binding; } + None => {} } } } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind { @@ -1149,12 +1135,8 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib _ => 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, binding); + rib.bindings.insert(ident, res); } self.ribs[ValueNS].push(function_value_rib); @@ -1274,12 +1256,10 @@ fn with_optional_trait_ref( } 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), binding); + self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res); self.ribs[ns].push(self_type_rib); f(self); self.ribs[ns].pop(); @@ -1490,7 +1470,7 @@ fn resolve_local(&mut self, local: &'ast Local) { /// 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) -> FxHashMap { + fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { let mut binding_map = FxHashMap::default(); pat.walk(&mut |pat| { @@ -1523,7 +1503,7 @@ fn is_base_res_local(&self, nid: NodeId) -> bool { /// 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]) -> Vec> { + fn check_consistent_bindings(&mut self, pats: &[P]) -> Vec { let mut missing_vars = FxHashMap::default(); let mut inconsistent_vars = FxHashMap::default(); @@ -1665,6 +1645,7 @@ fn resolve_pattern_inner( .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( @@ -1754,24 +1735,18 @@ fn fresh_binding( if already_bound_or { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. - self.innermost_rib_bindings(ValueNS)[&ident].res() + self.innermost_rib_bindings(ValueNS)[&ident] } else { let res = Res::Local(pat_id); if ident_valid { // A completely fresh binding add to the set if it's valid. - 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); + self.innermost_rib_bindings(ValueNS).insert(ident, res); } res } } - fn innermost_rib_bindings( - &mut self, - ns: Namespace, - ) -> &mut FxHashMap> { + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap { &mut self.ribs[ns].last_mut().unwrap().bindings } @@ -1788,17 +1763,22 @@ fn try_resolve_as_non_binding( // 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 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 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 res = binding.res(); match res { Res::SelfCtor(_) // See #70549. | Res::Def( @@ -1806,7 +1786,9 @@ fn try_resolve_as_non_binding( _, ) if is_syntactic_ambiguity => { // Disambiguate in favor of a unit struct/variant or constant pattern. - self.r.record_use(ident, binding, false); + if let Some(binding) = binding { + self.r.record_use(ident, binding, false); + } Some(res) } Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => { @@ -1815,6 +1797,7 @@ fn try_resolve_as_non_binding( // 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 { @@ -2054,15 +2037,19 @@ fn smart_resolve_path_fragment( } fn self_type_is_available(&mut self, span: Span) -> bool { - 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) + 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 } } fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool { let ident = Ident::new(kw::SelfLower, self_span); - self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span) - .map_or(false, |binding| binding.res() != Res::Err) + 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 } } /// 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 506f1549753..1748a9be8e1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1294,8 +1294,7 @@ fn lookup_typo_candidate( // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { // Locals and type parameters - for (ident, binding) in &rib.bindings { - let res = binding.res(); + for (ident, &res) in &rib.bindings { 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 042c6a92460..98c1355d05b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -373,6 +373,26 @@ fn visit_item(&mut self, item: &'tcx ast::Item) { } } +/// 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. @@ -898,6 +918,10 @@ 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, + /// Resolutions for nodes that have a single resolution. partial_res_map: NodeMap, /// Resolutions for import nodes, which have multiple resolutions in different namespaces. @@ -1308,6 +1332,7 @@ pub fn new( 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(), @@ -1333,8 +1358,13 @@ pub fn new( macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: (Res::Err, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(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, + }), crate_loader: CrateLoader::new(session, metadata_loader, crate_name), macro_names: FxHashSet::default(), @@ -1891,11 +1921,11 @@ fn resolve_ident_in_lexical_scope( record_used_id: Option, path_span: Span, ribs: &[Rib<'a>], - ) -> Result<&'a NameBinding<'a>, Determinacy> { + ) -> Option> { assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; if ident.name == kw::Empty { - return Ok(self.dummy_binding); + return Some(LexicalScopeBinding::Res(Res::Err)); } let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene @@ -1918,30 +1948,18 @@ fn resolve_ident_in_lexical_scope( // 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, &binding)) = - ribs[i].bindings.get_key_value(&rib_ident) + if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. - let res = self.validate_res_from_ribs( + return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( i, rib_ident, - binding.res(), + *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 { @@ -1960,7 +1978,7 @@ fn resolve_ident_in_lexical_scope( _ => break, } - let binding = self.resolve_ident_in_module_unadjusted( + let item = self.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -1968,9 +1986,9 @@ fn resolve_ident_in_lexical_scope( record_used, path_span, ); - if binding.is_ok() { + if let Ok(binding) = item { // The ident resolves to an item. - return binding; + return Some(LexicalScopeBinding::Item(binding)); } } self.early_resolve_ident_in_lexical_scope( @@ -1981,6 +1999,8 @@ fn resolve_ident_in_lexical_scope( record_used, path_span, ) + .ok() + .map(LexicalScopeBinding::Item) } fn hygienic_lexical_parent( @@ -2205,6 +2225,16 @@ fn resolve_path_with_ribs( 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 }; @@ -2283,8 +2313,12 @@ fn resolve_path_with_ribs( }; } + enum FindBindingResult<'a> { + Binding(Result<&'a NameBinding<'a>, Determinacy>), + PathResult(PathResult<'a>), + } let find_binding_in_ns = |this: &mut Self, ns| { - if let Some(module) = module { + let binding = if let Some(module) = module { this.resolve_ident_in_module( module, ident, @@ -2309,34 +2343,44 @@ fn resolve_path_with_ribs( } else { None }; - this.resolve_ident_in_lexical_scope( + match 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) }; - - match find_binding_in_ns(self, ns) { + let binding = match find_binding_in_ns(self, ns) { + FindBindingResult::PathResult(x) => return x, + FindBindingResult::Binding(binding) => binding, + }; + match binding { 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 @@ -2426,25 +2470,56 @@ fn resolve_path_with_ribs( .map_or(false, |c| c.is_ascii_uppercase()) { // Check whether the name refers to an item in the value namespace. - 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(""))], + 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(""))], format!("`{}` is defined here, but is not a type", ident), Applicability::MaybeIncorrect, - ) - }); + )) + } else { + None + } + } else { + None + }; (format!("use of undeclared type `{}`", ident), suggestion) } else { @@ -2482,7 +2557,9 @@ fn resolve_path_with_ribs( 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 Ok(binding) = find_binding_in_ns(self, ns_to_try) { + if let FindBindingResult::Binding(Ok(binding)) = + find_binding_in_ns(self, ns_to_try) + { let mut found = |what| { msg = format!( "expected {}, found {} `{}` in {}", @@ -2824,6 +2901,11 @@ fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { } } + 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) }