about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs52
-rw-r--r--tests/ui/suggestions/issue-109195.rs20
-rw-r--r--tests/ui/suggestions/issue-109195.stderr69
3 files changed, 141 insertions, 0 deletions
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 |     <String as Example>::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`.