about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-29 18:39:23 +0000
committerbors <bors@rust-lang.org>2023-12-29 18:39:23 +0000
commit3cdd004e55c869faa2b7b25efd3becf50346e7d6 (patch)
treebe2a5cb4df46dff9f1077b28f6e5903714c1407e
parent29abb90bbf4472d8a3bc032a838b20a85f5ed1e7 (diff)
parent9e9353c0da58315b6acc13891ca412ed6acfb513 (diff)
downloadrust-3cdd004e55c869faa2b7b25efd3becf50346e7d6.tar.gz
rust-3cdd004e55c869faa2b7b25efd3becf50346e7d6.zip
Auto merge of #118911 - Young-Flash:fix_issue_118819, r=fmease
fix: correct the args for `disambiguate the associated function` diagnostic

This is somehow silimar to https://github.com/rust-lang/rust/pull/118502, we shouldn't take receiver as first arg all the cases.

close https://github.com/rust-lang/rust/issues/118819
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs48
-rw-r--r--tests/ui/methods/disambiguate-associated-function-first-arg.rs49
-rw-r--r--tests/ui/methods/disambiguate-associated-function-first-arg.stderr67
-rw-r--r--tests/ui/methods/method-ambiguity-no-rcvr.stderr8
4 files changed, 148 insertions, 24 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 6530d828b3b..47fdd64796e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3306,6 +3306,7 @@ fn print_disambiguation_help<'tcx>(
     span: Span,
     item: ty::AssocItem,
 ) -> Option<String> {
+    let trait_impl_type = trait_ref.self_ty().peel_refs();
     let trait_ref = if item.fn_has_self_parameter {
         trait_ref.print_only_trait_name().to_string()
     } else {
@@ -3318,27 +3319,34 @@ fn print_disambiguation_help<'tcx>(
         {
             let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
             let item_name = item.ident(tcx);
-            let rcvr_ref = tcx
-                .fn_sig(item.def_id)
-                .skip_binder()
-                .skip_binder()
-                .inputs()
-                .get(0)
-                .and_then(|ty| ty.ref_mutability())
-                .map_or("", |mutbl| mutbl.ref_prefix_str());
-            let args = format!(
-                "({}{})",
-                rcvr_ref,
-                std::iter::once(receiver)
-                    .chain(args.iter())
-                    .map(|arg| tcx
-                        .sess
-                        .source_map()
-                        .span_to_snippet(arg.span)
-                        .unwrap_or_else(|_| { "_".to_owned() }))
-                    .collect::<Vec<_>>()
-                    .join(", "),
+            let first_input =
+                tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
+            let (first_arg_type, rcvr_ref) = (
+                first_input.map(|first| first.peel_refs()),
+                first_input
+                    .and_then(|ty| ty.ref_mutability())
+                    .map_or("", |mutbl| mutbl.ref_prefix_str()),
             );
+
+            // If the type of first arg of this assoc function is `Self` or current trait impl type or `arbitrary_self_types`, we need to take the receiver as args. Otherwise, we don't.
+            let args = if let Some(first_arg_type) = first_arg_type
+                && (first_arg_type == tcx.types.self_param
+                    || first_arg_type == trait_impl_type
+                    || item.fn_has_self_parameter)
+            {
+                Some(receiver)
+            } else {
+                None
+            }
+            .into_iter()
+            .chain(args)
+            .map(|arg| {
+                tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned())
+            })
+            .collect::<Vec<_>>()
+            .join(", ");
+
+            let args = format!("({}{})", rcvr_ref, args);
             err.span_suggestion_verbose(
                 span,
                 format!(
diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.rs b/tests/ui/methods/disambiguate-associated-function-first-arg.rs
new file mode 100644
index 00000000000..4c8192fc14b
--- /dev/null
+++ b/tests/ui/methods/disambiguate-associated-function-first-arg.rs
@@ -0,0 +1,49 @@
+struct A {}
+
+fn main() {
+    let _a = A {};
+    _a.new(1);
+    //~^ ERROR no method named `new` found for struct `A` in the current scope
+}
+
+trait M {
+    fn new(_a: i32);
+}
+impl M for A {
+    fn new(_a: i32) {}
+}
+
+trait N {
+    fn new(_a: Self, _b: i32);
+}
+impl N for A {
+    fn new(_a: Self, _b: i32) {}
+}
+
+trait O {
+    fn new(_a: Self, _b: i32);
+}
+impl O for A {
+    fn new(_a: A, _b: i32) {}
+}
+
+struct S;
+
+trait TraitA {
+    fn f(self);
+}
+trait TraitB {
+    fn f(self);
+}
+
+impl<T> TraitA for T {
+    fn f(self) {}
+}
+impl<T> TraitB for T {
+    fn f(self) {}
+}
+
+fn test() {
+    S.f();
+   //~^ multiple applicable items in scope
+}
diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.stderr b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr
new file mode 100644
index 00000000000..341b7a91003
--- /dev/null
+++ b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr
@@ -0,0 +1,67 @@
+error[E0599]: no method named `new` found for struct `A` in the current scope
+  --> $DIR/disambiguate-associated-function-first-arg.rs:5:8
+   |
+LL | struct A {}
+   | -------- method `new` not found for this struct
+...
+LL |     _a.new(1);
+   |        ^^^ this is an associated function, not a method
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in the trait `M`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:10:5
+   |
+LL |     fn new(_a: i32);
+   |     ^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in the trait `N`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:17:5
+   |
+LL |     fn new(_a: Self, _b: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #3 is defined in the trait `O`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:24:5
+   |
+LL |     fn new(_a: Self, _b: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the associated function for candidate #1
+   |
+LL |     <A as M>::new(1);
+   |     ~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+   |
+LL |     <A as N>::new(_a, 1);
+   |     ~~~~~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #3
+   |
+LL |     <A as O>::new(_a, 1);
+   |     ~~~~~~~~~~~~~~~~~~~~
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/disambiguate-associated-function-first-arg.rs:47:7
+   |
+LL |     S.f();
+   |       ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl of the trait `TraitA` for the type `T`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:40:5
+   |
+LL |     fn f(self) {}
+   |     ^^^^^^^^^^
+note: candidate #2 is defined in an impl of the trait `TraitB` for the type `T`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:43:5
+   |
+LL |     fn f(self) {}
+   |     ^^^^^^^^^^
+help: disambiguate the method for candidate #1
+   |
+LL |     TraitA::f(S);
+   |     ~~~~~~~~~~~~
+help: disambiguate the method for candidate #2
+   |
+LL |     TraitB::f(S);
+   |     ~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0034, E0599.
+For more information about an error, try `rustc --explain E0034`.
diff --git a/tests/ui/methods/method-ambiguity-no-rcvr.stderr b/tests/ui/methods/method-ambiguity-no-rcvr.stderr
index 73f6043f256..3b6eb07393a 100644
--- a/tests/ui/methods/method-ambiguity-no-rcvr.stderr
+++ b/tests/ui/methods/method-ambiguity-no-rcvr.stderr
@@ -20,12 +20,12 @@ LL |     fn foo() {}
    |     ^^^^^^^^
 help: disambiguate the associated function for candidate #1
    |
-LL |     <Qux as Foo>::foo(Qux);
-   |     ~~~~~~~~~~~~~~~~~~~~~~
+LL |     <Qux as Foo>::foo();
+   |     ~~~~~~~~~~~~~~~~~~~
 help: disambiguate the associated function for candidate #2
    |
-LL |     <Qux as FooBar>::foo(Qux);
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     <Qux as FooBar>::foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error