From f1b508cff7c735286fbf8204e4ea43503d5a3663 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 14 Jan 2024 18:44:55 +0800 Subject: [PATCH 1/3] fix: correct suggestion arg for impl trait --- .../rustc_hir_typeck/src/method/suggest.rs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 47fdd64796e..bbebc475279 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1587,23 +1587,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, impl_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 == impl_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 From c0a5a859b9d5449ae82b5586c786b94e88314c5b Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 14 Jan 2024 18:54:07 +0800 Subject: [PATCH 2/3] test: add test case for impl trait arg suggestion --- ...suggest-assoc-fn-call-for-impl-trait.fixed | 29 +++++++++ .../suggest-assoc-fn-call-for-impl-trait.rs | 29 +++++++++ ...uggest-assoc-fn-call-for-impl-trait.stderr | 60 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed create mode 100644 tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs create mode 100644 tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr 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`. From 8b3a681a34ed183510af5365e9fab17cca06baf7 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sat, 27 Jan 2024 10:24:45 +0800 Subject: [PATCH 3/3] minor: pick a suitable var name --- compiler/rustc_hir_typeck/src/method/suggest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index bbebc475279..8feef6bc97e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1588,7 +1588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let SelfSource::MethodCall(_) = source { let first_arg = static_candidates.get(0).and_then(|candidate_source| { - let (assoc_did, impl_ty) = match candidate_source { + let (assoc_did, self_ty) = match candidate_source { CandidateSource::Impl(impl_did) => { (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity()) } @@ -1606,7 +1606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sig.inputs().skip_binder().get(0).and_then(|first| { // if the type of first arg is the same as the current impl type, we should take the first arg into assoc function let first_ty = first.peel_refs(); - if first_ty == impl_ty || first_ty == self.tcx.types.self_param { + 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