diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 89f39897ea8..d69f366a66c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -29,6 +29,7 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::query::Key; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty, TyCtxt, TypeVisitableExt, @@ -1373,6 +1374,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .emit() // Already reported in an earlier stage. } else { + // suggest methods that look similar to the path + // e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195) + for (_, node) in tcx.hir().parent_iter(qself.hir_id) { + if let hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::TypeRelative( + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::TypeRelative( + _, + hir::PathSegment { ident: ident2, .. }, + )), + .. + }, + hir::PathSegment { ident: ident3, .. }, + )), + .. + }) = node + { + let name = format!("{ident2}_{ident3}"); + if if let Some(ty_def_id) = qself_ty.ty_def_id() + && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id) + && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx + .associated_items(inherent_impl) + .filter_by_name_unhygienic(Symbol::intern(&name)) + .next() + { + true + } else { + qself_ty.is_str() + && ["from_utf8", "from_utf8_mut"].contains(&name.as_str()) + } { + let reported = struct_span_code_err!( + tcx.dcx(), + span, + E0223, + "ambiguous associated type" + ) + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("you might have meant to use `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit(); + self.set_tainted_by_errors(reported); + return Err(reported); + } + } + } + let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs new file mode 100644 index 00000000000..badb859dbb7 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.rs @@ -0,0 +1,20 @@ +fn main() { + String::from::utf8; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + String::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + String::from::utf16(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf16` + String::from::method_that_doesnt_exist(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` + str::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8` + str::from::utf8_mut(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP you might have meant to use `from_utf8_mut` +} diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr new file mode 100644 index 00000000000..5c9ef9f98f5 --- /dev/null +++ b/tests/ui/suggestions/issue-109195.stderr @@ -0,0 +1,69 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:2:5 + | +LL | String::from::utf8; + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | String::from_utf8; + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:5:5 + | +LL | String::from::utf8(); + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | String::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:8:5 + | +LL | String::from::utf16(); + | ^^^^^^^^^^^^ + | +help: you might have meant to use `from_utf16` + | +LL | String::from_utf16(); + | ~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:11:5 + | +LL | String::from::method_that_doesnt_exist(); + | ^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path + | +LL | ::from::method_that_doesnt_exist(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:14:5 + | +LL | str::from::utf8(); + | ^^^^^^^^^ + | +help: you might have meant to use `from_utf8` + | +LL | str::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/issue-109195.rs:17:5 + | +LL | str::from::utf8_mut(); + | ^^^^^^^^^ + | +help: you might have meant to use `from_utf8_mut` + | +LL | str::from_utf8_mut(); + | ~~~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0223`.