1
Fork 0

Suggest typos when trait path expression is typod

This commit is contained in:
Michael Goulet 2025-01-11 18:10:32 +00:00
parent 336209eef1
commit 4486a19007
3 changed files with 79 additions and 2 deletions

View file

@ -2,10 +2,12 @@ use rustc_ast::TraitObjectSyntax;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions}; use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_lint_defs::Applicability; use rustc_lint_defs::Applicability;
use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS; use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
use super::HirTyLowerer; use super::HirTyLowerer;
@ -86,7 +88,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Check if the impl trait that we are considering is an impl of a local trait. // Check if the impl trait that we are considering is an impl of a local trait.
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag); self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
// In case there is an associate type with the same name self.maybe_suggest_typoed_method(
self_ty,
poly_trait_ref.trait_ref.trait_def_id(),
&mut diag,
);
// In case there is an associated type with the same name
// Add the suggestion to this error // Add the suggestion to this error
if let Some(mut sugg) = if let Some(mut sugg) =
tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion) tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
@ -343,4 +350,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
); );
} }
} }
fn maybe_suggest_typoed_method(
&self,
self_ty: &hir::Ty<'_>,
trait_def_id: Option<DefId>,
diag: &mut Diag<'_>,
) {
let tcx = self.tcx();
let Some(trait_def_id) = trait_def_id else {
return;
};
let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
..
}) = tcx.parent_hir_node(self_ty.hir_id)
else {
return;
};
if path_ty.hir_id != self_ty.hir_id {
return;
}
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
.map(|cand| cand.name)
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(
segment.ident.span,
format!(
"you may have misspelled this associated item, causing `{}` \
to be interpreted as a type rather than a trait",
tcx.item_name(trait_def_id),
),
typo,
Applicability::MaybeIncorrect,
);
}
}
} }

View file

@ -0,0 +1,12 @@
//@ edition: 2021
trait Trait {
fn typo() -> Self;
}
fn main() {
let () = Trait::typoe();
//~^ ERROR expected a type, found a trait
//~| HELP you can add the `dyn` keyword if you want a trait object
//~| HELP you may have misspelled this associated item
}

View file

@ -0,0 +1,18 @@
error[E0782]: expected a type, found a trait
--> $DIR/misspelled-associated-item.rs:8:14
|
LL | let () = Trait::typoe();
| ^^^^^
|
help: you can add the `dyn` keyword if you want a trait object
|
LL | let () = <dyn Trait>::typoe();
| ++++ +
help: you may have misspelled this associated item, causing `Trait` to be interpreted as a type rather than a trait
|
LL | let () = Trait::typo();
| ~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0782`.