Skip to content

Commit 55503a1

Browse files
authored
Rollup merge of #135374 - compiler-errors:typo-trait-method, r=fee1-dead
Suggest typo fix when trait path expression is typo'ed When users write something like `Default::defualt()` (notice the typo), failure to resolve the erroneous `defualt` item will cause resolution + lowering to interpret this as a type-dependent path whose self type is `Default` which is a trait object without `dyn`, rather than a trait function like `<_ as Default>::default()`. Try to provide a bit of guidance in this situation when we can detect the typo. Fixes #135349
2 parents 08968a4 + 4486a19 commit 55503a1

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs

+49-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ use rustc_ast::TraitObjectSyntax;
22
use rustc_errors::codes::*;
33
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
44
use rustc_hir as hir;
5-
use rustc_hir::def::{DefKind, Res};
5+
use rustc_hir::def::{DefKind, Namespace, Res};
6+
use rustc_hir::def_id::DefId;
67
use rustc_lint_defs::Applicability;
78
use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS;
89
use rustc_span::Span;
10+
use rustc_span::edit_distance::find_best_match_for_name;
911
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
1012

1113
use super::HirTyLowerer;
@@ -86,7 +88,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8688
// Check if the impl trait that we are considering is an impl of a local trait.
8789
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
8890
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
89-
// In case there is an associate type with the same name
91+
self.maybe_suggest_typoed_method(
92+
self_ty,
93+
poly_trait_ref.trait_ref.trait_def_id(),
94+
&mut diag,
95+
);
96+
// In case there is an associated type with the same name
9097
// Add the suggestion to this error
9198
if let Some(mut sugg) =
9299
tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
@@ -343,4 +350,44 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
343350
);
344351
}
345352
}
353+
354+
fn maybe_suggest_typoed_method(
355+
&self,
356+
self_ty: &hir::Ty<'_>,
357+
trait_def_id: Option<DefId>,
358+
diag: &mut Diag<'_>,
359+
) {
360+
let tcx = self.tcx();
361+
let Some(trait_def_id) = trait_def_id else {
362+
return;
363+
};
364+
let hir::Node::Expr(hir::Expr {
365+
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
366+
..
367+
}) = tcx.parent_hir_node(self_ty.hir_id)
368+
else {
369+
return;
370+
};
371+
if path_ty.hir_id != self_ty.hir_id {
372+
return;
373+
}
374+
let names: Vec<_> = tcx
375+
.associated_items(trait_def_id)
376+
.in_definition_order()
377+
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
378+
.map(|cand| cand.name)
379+
.collect();
380+
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
381+
diag.span_suggestion_verbose(
382+
segment.ident.span,
383+
format!(
384+
"you may have misspelled this associated item, causing `{}` \
385+
to be interpreted as a type rather than a trait",
386+
tcx.item_name(trait_def_id),
387+
),
388+
typo,
389+
Applicability::MaybeIncorrect,
390+
);
391+
}
392+
}
346393
}

Diff for: tests/ui/dyn-keyword/misspelled-associated-item.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ edition: 2021
2+
3+
trait Trait {
4+
fn typo() -> Self;
5+
}
6+
7+
fn main() {
8+
let () = Trait::typoe();
9+
//~^ ERROR expected a type, found a trait
10+
//~| HELP you can add the `dyn` keyword if you want a trait object
11+
//~| HELP you may have misspelled this associated item
12+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0782]: expected a type, found a trait
2+
--> $DIR/misspelled-associated-item.rs:8:14
3+
|
4+
LL | let () = Trait::typoe();
5+
| ^^^^^
6+
|
7+
help: you can add the `dyn` keyword if you want a trait object
8+
|
9+
LL | let () = <dyn Trait>::typoe();
10+
| ++++ +
11+
help: you may have misspelled this associated item, causing `Trait` to be interpreted as a type rather than a trait
12+
|
13+
LL | let () = Trait::typo();
14+
| ~~~~
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0782`.

0 commit comments

Comments
 (0)