X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_resolve%2Fsrc%2Flate%2Fdiagnostics.rs;h=ffa7cb0c9d2333eef2ebec8baa90e99c7bf32c6e;hb=4bbb163b5d248bef036670d952f1c00dd812a7e2;hp=c05f89a65755f8630c1573468522826d0879d49f;hpb=d8d01e32168a24862b9ed2b6a6b7eb0e82fbcfce;p=rust.git diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c05f89a6575..ffa7cb0c9d2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate { } /// Only used for diagnostics. +#[derive(Debug)] struct BaseError { msg: String, fallback_label: String, @@ -140,6 +141,22 @@ struct BaseError { suggestion: Option<(Span, &'static str, String)>, } +#[derive(Debug)] +enum TypoCandidate { + Typo(TypoSuggestion), + Shadowed(Res), + None, +} + +impl TypoCandidate { + fn to_opt_suggestion(self) -> Option { + match self { + TypoCandidate::Typo(sugg) => Some(sugg), + TypoCandidate::Shadowed(_) | TypoCandidate::None => None, + } + } +} + impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { @@ -496,7 +513,8 @@ fn try_lookup_name_relaxed( } // Try Levenshtein algorithm. - let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + let typo_sugg = + self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion(); if path.len() == 1 && self.self_type_is_available() { 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); @@ -660,7 +678,18 @@ fn suggest_typo( let is_expected = &|res| source.is_expected(res); let ident_span = path.last().map_or(span, |ident| ident.ident.span); let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + if let TypoCandidate::Shadowed(res) = typo_sugg + && let Some(id) = res.opt_def_id() + && let Some(sugg_span) = self.r.opt_span(id) + { + err.span_label( + sugg_span, + format!("you might have meant to refer to this {}", res.descr()), + ); + return true; + } let mut fallback = false; + let typo_sugg = typo_sugg.to_opt_suggestion(); if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) { fallback = true; match self.diagnostic_metadata.current_let_binding { @@ -968,11 +997,10 @@ fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnost let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false; }; - if !(matches!( - partial_res.base_res(), - hir::def::Res::Def(hir::def::DefKind::AssocTy, _) - ) && partial_res.unresolved_segments() == 0) - { + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) + ) { return false; } (ty, position, path) @@ -986,11 +1014,10 @@ fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnost let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { return false; }; - if !(matches!( - partial_res.base_res(), - hir::def::Res::Def(hir::def::DefKind::TyParam, _) - ) && partial_res.unresolved_segments() == 0) - { + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) + ) { return false; } if let ( @@ -1518,20 +1545,14 @@ fn extract_node_id(t: &Ty) -> Option { { // 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 | 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.node) - { - return Some(AssocSuggestion::Field); - } + if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) = + resolution.full_res() + { + if let Some(field_names) = self.r.field_names.get(&did) { + if field_names.iter().any(|&field_name| ident.name == field_name.node) { + return Some(AssocSuggestion::Field); } } - _ => {} } } } @@ -1589,22 +1610,38 @@ fn lookup_typo_candidate( path: &[Segment], ns: Namespace, filter_fn: &impl Fn(Res) -> bool, - ) -> Option { + ) -> TypoCandidate { let mut names = Vec::new(); if path.len() == 1 { + let mut ctxt = path.last().unwrap().ident.span.ctxt(); + // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { + let rib_ctxt = if rib.kind.contains_params() { + ctxt.normalize_to_macros_2_0() + } else { + ctxt.normalize_to_macro_rules() + }; + // Locals and type parameters for (ident, &res) in &rib.bindings { - if filter_fn(res) { + if filter_fn(res) && ident.span.ctxt() == rib_ctxt { names.push(TypoSuggestion::typo_from_res(ident.name, res)); } } + + if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ctxt.remove_mark(); + continue; + } + // Items in scope if let RibKind::ModuleRibKind(module) = rib.kind { // Items from this module - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); if let ModuleKind::Block = module.kind { // We can see through blocks @@ -1630,7 +1667,7 @@ fn lookup_typo_candidate( })); if let Some(prelude) = self.r.prelude { - self.r.add_module_candidates(prelude, &mut names, &filter_fn); + self.r.add_module_candidates(prelude, &mut names, &filter_fn, None); } } break; @@ -1649,7 +1686,7 @@ fn lookup_typo_candidate( if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, Some(TypeNS), None) { - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, None); } } @@ -1662,10 +1699,17 @@ fn lookup_typo_candidate( name, None, ) { - Some(found) if found != name => { - names.into_iter().find(|suggestion| suggestion.candidate == found) + Some(found) => { + let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else { + return TypoCandidate::None; + }; + if found == name { + TypoCandidate::Shadowed(sugg.res) + } else { + TypoCandidate::Typo(sugg) + } } - _ => None, + _ => TypoCandidate::None, } }