about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-01-27 10:48:47 +0100
committerGitHub <noreply@github.com>2024-01-27 10:48:47 +0100
commitc6f0a5cfe376b365523bd080c9886301c7e973e4 (patch)
tree85eb5b9824f07b6bce662c69eb9b1d896ee350a1
parentb35a3f89bd4cb5e9e7cc5b62de0e1334f04a6c5b (diff)
parent8b3a681a34ed183510af5365e9fab17cca06baf7 (diff)
downloadrust-c6f0a5cfe376b365523bd080c9886301c7e973e4.tar.gz
rust-c6f0a5cfe376b365523bd080c9886301c7e973e4.zip
Rollup merge of #119957 - Young-Flash:fix, r=fmease
fix: correct suggestion arg for impl trait

follow up https://github.com/rust-lang/rust/pull/118502, close https://github.com/rust-lang/rust/issues/119775
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs28
-rw-r--r--tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed29
-rw-r--r--tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs29
-rw-r--r--tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr60
4 files changed, 137 insertions, 9 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 0b8a25eedaf..47f6e3f934e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1601,23 +1601,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.ty_to_value_string(rcvr_ty.peel_refs())
         };
         if let SelfSource::MethodCall(_) = source {
-            let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
-                && let Some(assoc) = self.associated_value(*impl_did, item_name)
-                && assoc.kind == ty::AssocKind::Fn
-            {
+            let first_arg = static_candidates.get(0).and_then(|candidate_source| {
+                let (assoc_did, self_ty) = match candidate_source {
+                    CandidateSource::Impl(impl_did) => {
+                        (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity())
+                    }
+                    CandidateSource::Trait(trait_did) => (*trait_did, rcvr_ty),
+                };
+
+                let assoc = self.associated_value(assoc_did, item_name)?;
+                if assoc.kind != ty::AssocKind::Fn {
+                    return None;
+                }
+
+                // for CandidateSource::Impl, `Self` will be instantiated to a concrete type
+                // but for CandidateSource::Trait, `Self` is still `Self`
                 let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
                 sig.inputs().skip_binder().get(0).and_then(|first| {
-                    let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
                     // if the type of first arg is the same as the current impl type, we should take the first arg into assoc function
-                    if first.peel_refs() == impl_ty {
+                    let first_ty = first.peel_refs();
+                    if first_ty == self_ty || first_ty == self.tcx.types.self_param {
                         Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
                     } else {
                         None
                     }
                 })
-            } else {
-                None
-            };
+            });
+
             let mut applicability = Applicability::MachineApplicable;
             let args = if let SelfSource::MethodCall(receiver) = source
                 && let Some(args) = args
diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed
new file mode 100644
index 00000000000..86ac07a93a3
--- /dev/null
+++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+
+struct A {
+
+}
+
+trait M {
+    fn foo(_a: Self);
+    fn bar(_a: Self);
+    fn baz(_a: i32);
+}
+
+impl M for A {
+    fn foo(_a: Self) {}
+    fn bar(_a: A) {}
+    fn baz(_a: i32) {}
+}
+
+fn main() {
+    let _a = A {};
+    A::foo(_a);
+    //~^ ERROR no method named `foo` found
+    A::baz(0);
+    //~^ ERROR no method named `baz` found
+
+    let _b = A {};
+    A::bar(_b);
+    //~^ ERROR no method named `bar` found
+}
diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs
new file mode 100644
index 00000000000..9a57ffb7740
--- /dev/null
+++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs
@@ -0,0 +1,29 @@
+// run-rustfix
+
+struct A {
+
+}
+
+trait M {
+    fn foo(_a: Self);
+    fn bar(_a: Self);
+    fn baz(_a: i32);
+}
+
+impl M for A {
+    fn foo(_a: Self) {}
+    fn bar(_a: A) {}
+    fn baz(_a: i32) {}
+}
+
+fn main() {
+    let _a = A {};
+    _a.foo();
+    //~^ ERROR no method named `foo` found
+    _a.baz(0);
+    //~^ ERROR no method named `baz` found
+
+    let _b = A {};
+    _b.bar();
+    //~^ ERROR no method named `bar` found
+}
diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr
new file mode 100644
index 00000000000..0df2b08d3be
--- /dev/null
+++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr
@@ -0,0 +1,60 @@
+error[E0599]: no method named `foo` found for struct `A` in the current scope
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:21:8
+   |
+LL | struct A {
+   | -------- method `foo` not found for this struct
+...
+LL |     _a.foo();
+   |     ---^^^--
+   |     |  |
+   |     |  this is an associated function, not a method
+   |     help: use associated function syntax instead: `A::foo(_a)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in the trait `M`
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:8:5
+   |
+LL |     fn foo(_a: Self);
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0599]: no method named `baz` found for struct `A` in the current scope
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8
+   |
+LL | struct A {
+   | -------- method `baz` not found for this struct
+...
+LL |     _a.baz(0);
+   |     ---^^^---
+   |     |  |
+   |     |  this is an associated function, not a method
+   |     help: use associated function syntax instead: `A::baz(0)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in the trait `M`
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:10:5
+   |
+LL |     fn baz(_a: i32);
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0599]: no method named `bar` found for struct `A` in the current scope
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8
+   |
+LL | struct A {
+   | -------- method `bar` not found for this struct
+...
+LL |     _b.bar();
+   |     ---^^^--
+   |     |  |
+   |     |  this is an associated function, not a method
+   |     help: use associated function syntax instead: `A::bar(_b)`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in the trait `M`
+  --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:9:5
+   |
+LL |     fn bar(_a: Self);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.