From 6c6a2c1ef75aaa2fd3b813e3a12dd7908bdd94b1 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Wed, 13 Dec 2023 19:57:42 +0800 Subject: [PATCH 1/3] fix: correct the args for `disambiguate the associated function` diagnostic --- .../rustc_hir_typeck/src/method/suggest.rs | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8fb703fa7f52e..503fb13664ae5 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3312,6 +3312,7 @@ fn print_disambiguation_help<'tcx>( span: Span, item: ty::AssocItem, ) -> Option { + let trait_impl_type = trait_ref.self_ty(); let trait_ref = if item.fn_has_self_parameter { trait_ref.print_only_trait_name().to_string() } else { @@ -3324,6 +3325,13 @@ 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 first_arg_type = tcx + .fn_sig(item.def_id) + .instantiate_identity() + .skip_binder() + .inputs() + .get(0) + .and_then(|first| Some(first.peel_refs())); let rcvr_ref = tcx .fn_sig(item.def_id) .skip_binder() @@ -3332,19 +3340,22 @@ fn print_disambiguation_help<'tcx>( .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::>() - .join(", "), - ); + // If the type of first arg of this assoc function is `Self` or current trait impl type, we need to take the receiver as args. Otherwise, we don't. + let args = if let Some(t) = first_arg_type + && (t.to_string() == "Self" || t == trait_impl_type) + { + std::iter::once(receiver).chain(args.iter()).collect::>() + } else { + args.iter().collect::>() + } + .iter() + .map(|arg| { + tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned()) + }) + .collect::>() + .join(", "); + + let args = format!("({}{})", rcvr_ref, args); err.span_suggestion_verbose( span, format!( From ffd619a69521b034ea9d37f5f128055dbea35671 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Wed, 13 Dec 2023 19:58:08 +0800 Subject: [PATCH 2/3] test: add test case for `disambiguate the associated function` diagnostic --- ...ambiguate-associated-function-first-arg.rs | 28 +++++++++++++ ...guate-associated-function-first-arg.stderr | 41 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/ui/methods/disambiguate-associated-function-first-arg.rs create mode 100644 tests/ui/methods/disambiguate-associated-function-first-arg.stderr 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 0000000000000..1f8aa07b68578 --- /dev/null +++ b/tests/ui/methods/disambiguate-associated-function-first-arg.rs @@ -0,0 +1,28 @@ +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) {} +} 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 0000000000000..b66ee7b8f4dee --- /dev/null +++ b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr @@ -0,0 +1,41 @@ +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 | ::new(1); + | ~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | ::new(_a, 1); + | ~~~~~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #3 + | +LL | ::new(_a, 1); + | ~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. From 9e9353c0da58315b6acc13891ca412ed6acfb513 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Wed, 27 Dec 2023 15:47:57 +0800 Subject: [PATCH 3/3] fix broken CI and code review --- .../rustc_hir_typeck/src/method/suggest.rs | 41 +++++++++---------- ...ambiguate-associated-function-first-arg.rs | 21 ++++++++++ ...guate-associated-function-first-arg.stderr | 30 +++++++++++++- .../methods/method-ambiguity-no-rcvr.stderr | 8 ++-- 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 503fb13664ae5..c355e78ecba08 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3312,7 +3312,7 @@ fn print_disambiguation_help<'tcx>( span: Span, item: ty::AssocItem, ) -> Option { - let trait_impl_type = trait_ref.self_ty(); + 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 { @@ -3325,30 +3325,27 @@ 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 first_arg_type = tcx - .fn_sig(item.def_id) - .instantiate_identity() - .skip_binder() - .inputs() - .get(0) - .and_then(|first| Some(first.peel_refs())); - 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()); - // If the type of first arg of this assoc function is `Self` or current trait impl type, we need to take the receiver as args. Otherwise, we don't. - let args = if let Some(t) = first_arg_type - && (t.to_string() == "Self" || t == trait_impl_type) + 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) { - std::iter::once(receiver).chain(args.iter()).collect::>() + Some(receiver) } else { - args.iter().collect::>() + None } - .iter() + .into_iter() + .chain(args) .map(|arg| { tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned()) }) diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.rs b/tests/ui/methods/disambiguate-associated-function-first-arg.rs index 1f8aa07b68578..4c8192fc14bd3 100644 --- a/tests/ui/methods/disambiguate-associated-function-first-arg.rs +++ b/tests/ui/methods/disambiguate-associated-function-first-arg.rs @@ -26,3 +26,24 @@ trait O { impl O for A { fn new(_a: A, _b: i32) {} } + +struct S; + +trait TraitA { + fn f(self); +} +trait TraitB { + fn f(self); +} + +impl TraitA for T { + fn f(self) {} +} +impl 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 index b66ee7b8f4dee..341b7a9100329 100644 --- a/tests/ui/methods/disambiguate-associated-function-first-arg.stderr +++ b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr @@ -36,6 +36,32 @@ help: disambiguate the associated function for candidate #3 LL | ::new(_a, 1); | ~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 1 previous error +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 -For more information about this error, try `rustc --explain E0599`. +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 73f6043f256ea..3b6eb07393ac8 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 | ::foo(Qux); - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | ::foo(); + | ~~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | ::foo(Qux); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | ::foo(); + | ~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error