diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5d868ebec944..5029c3399632 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -58,16 +58,32 @@ pub(crate) enum SuggestionTarget { #[derive(Debug)] pub(crate) struct TypoSuggestion { pub candidate: Symbol, + /// The source location where the name is defined; None if the name is not defined + /// in source e.g. primitives + pub span: Option, pub res: Res, pub target: SuggestionTarget, } impl TypoSuggestion { - pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion { - Self { candidate, res, target: SuggestionTarget::SimilarlyNamed } + pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion { + Self { + candidate: ident.name, + span: Some(ident.span), + res, + target: SuggestionTarget::SimilarlyNamed, + } } - pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion { - Self { candidate, res, target: SuggestionTarget::SingleItem } + pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion { + Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed } + } + pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion { + Self { + candidate: ident.name, + span: Some(ident.span), + res, + target: SuggestionTarget::SingleItem, + } } } @@ -490,7 +506,7 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_res(key.ident.name, res)); + names.push(TypoSuggestion::typo_from_ident(key.ident, res)); } } } @@ -1145,7 +1161,7 @@ impl<'a> Resolver<'a> { .get(&expn_id) .into_iter() .flatten() - .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)), + .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)), ); } } @@ -1164,7 +1180,7 @@ impl<'a> Resolver<'a> { suggestions.extend( ext.helper_attrs .iter() - .map(|name| TypoSuggestion::typo_from_res(*name, res)), + .map(|name| TypoSuggestion::typo_from_name(*name, res)), ); } } @@ -1174,8 +1190,8 @@ impl<'a> Resolver<'a> { if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { let res = macro_rules_binding.binding.res(); if filter_fn(res) { - suggestions.push(TypoSuggestion::typo_from_res( - macro_rules_binding.ident.name, + suggestions.push(TypoSuggestion::typo_from_ident( + macro_rules_binding.ident, res, )) } @@ -1193,7 +1209,7 @@ impl<'a> Resolver<'a> { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { let res = binding.res(); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res)) }, )); } @@ -1203,14 +1219,14 @@ impl<'a> Resolver<'a> { suggestions.extend( BUILTIN_ATTRIBUTES .iter() - .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)), + .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)), ); } } Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) })); } Scope::ToolPrelude => { @@ -1218,7 +1234,7 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_tools .iter() - .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)), + .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)), ); } Scope::StdLibPrelude => { @@ -1235,7 +1251,8 @@ impl<'a> Resolver<'a> { Scope::BuiltinTypes => { suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| { let res = Res::PrimTy(*prim_ty); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res)) + filter_fn(res) + .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res)) })) } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 850f023b1c16..8da09489b1f1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -150,7 +150,7 @@ struct BaseError { #[derive(Debug)] enum TypoCandidate { Typo(TypoSuggestion), - Shadowed(Res), + Shadowed(Res, Option), None, } @@ -158,7 +158,7 @@ impl TypoCandidate { fn to_opt_suggestion(self) -> Option { match self { TypoCandidate::Typo(sugg) => Some(sugg), - TypoCandidate::Shadowed(_) | TypoCandidate::None => None, + TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None, } } } @@ -691,10 +691,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { 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) - { + if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg { err.span_label( sugg_span, format!("you might have meant to refer to this {}", res.descr()), @@ -973,10 +970,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect(); if targets.len() == 1 { let target = targets[0]; - return Some(TypoSuggestion::single_item_from_res( - target.0.ident.name, - target.1, - )); + return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } } } @@ -1618,7 +1612,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // Locals and type parameters for (ident, &res) in &rib.bindings { if filter_fn(res) && ident.span.ctxt() == rib_ctxt { - names.push(TypoSuggestion::typo_from_res(ident.name, res)); + names.push(TypoSuggestion::typo_from_ident(*ident, res)); } } @@ -1647,9 +1641,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Res::Def(DefKind::Mod, crate_id.as_def_id()); if filter_fn(crate_mod) { - Some(TypoSuggestion::typo_from_res( - ident.name, crate_mod, - )) + Some(TypoSuggestion::typo_from_ident(*ident, crate_mod)) } else { None } @@ -1668,7 +1660,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // Add primitive types to the mix if filter_fn(Res::PrimTy(PrimTy::Bool)) { names.extend(PrimTy::ALL.iter().map(|prim_ty| { - TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty)) + TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty)) })) } } else { @@ -1695,7 +1687,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { return TypoCandidate::None; }; if found == name { - TypoCandidate::Shadowed(sugg.res) + TypoCandidate::Shadowed(sugg.res, sugg.span) } else { TypoCandidate::Typo(sugg) }