Provide placeholder generic arguments for traits in "no method found for type parameter" suggestions

This commit is contained in:
dianne 2024-11-01 19:47:07 -07:00
parent de27914e8e
commit 02add7d0fb
4 changed files with 137 additions and 21 deletions

View file

@ -4,6 +4,7 @@
#![feature(array_windows)] #![feature(array_windows)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(never_type)] #![feature(never_type)]
#![feature(try_blocks)] #![feature(try_blocks)]

View file

@ -3874,22 +3874,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param.name.ident(), param.name.ident(),
)); ));
let bounds_span = hir_generics.bounds_span_for_suggestions(def_id); let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
let mut applicability = Applicability::MaybeIncorrect;
// Format the path of each suggested candidate, providing placeholders
// for any generic arguments without defaults.
let candidate_strs: Vec<_> = candidates
.iter()
.map(|cand| {
let cand_path = self.tcx.def_path_str(cand.def_id);
let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
let cand_args: String = cand_params
.iter()
.skip(1)
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Type {
has_default: true,
..
}
| ty::GenericParamDefKind::Const {
has_default: true,
..
} => None,
_ => Some(param.name.as_str()),
})
.intersperse(", ")
.collect();
if cand_args.is_empty() {
cand_path
} else {
applicability = Applicability::HasPlaceholders;
format!("{cand_path}</* {cand_args} */>")
}
})
.collect();
if rcvr_ty.is_ref() if rcvr_ty.is_ref()
&& param.is_impl_trait() && param.is_impl_trait()
&& let Some((bounds_span, _)) = bounds_span && let Some((bounds_span, _)) = bounds_span
{ {
err.multipart_suggestions( err.multipart_suggestions(
msg, msg,
candidates.iter().map(|t| { candidate_strs.iter().map(|cand| {
vec![ vec![
(param.span.shrink_to_lo(), "(".to_string()), (param.span.shrink_to_lo(), "(".to_string()),
( (bounds_span, format!(" + {cand})")),
bounds_span,
format!(" + {})", self.tcx.def_path_str(t.def_id)),
),
] ]
}), }),
Applicability::MaybeIncorrect, applicability,
); );
return; return;
} }
@ -3905,16 +3935,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(param.span.shrink_to_hi(), Introducer::Colon, None) (param.span.shrink_to_hi(), Introducer::Colon, None)
}; };
let all_suggs = candidates.iter().map(|cand| { let all_suggs = candidate_strs.iter().map(|cand| {
let suggestion = format!( let suggestion = format!("{} {cand}", match introducer {
"{} {}", Introducer::Plus => " +",
match introducer { Introducer::Colon => ":",
Introducer::Plus => " +", Introducer::Nothing => "",
Introducer::Colon => ":", },);
Introducer::Nothing => "",
},
self.tcx.def_path_str(cand.def_id)
);
let mut suggs = vec![]; let mut suggs = vec![];
@ -3928,11 +3954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggs suggs
}); });
err.multipart_suggestions( err.multipart_suggestions(msg, all_suggs, applicability);
msg,
all_suggs,
Applicability::MaybeIncorrect,
);
return; return;
} }

View file

@ -0,0 +1,30 @@
/// Tests that suggestions to add trait bounds that would enable using a method include appropriate
/// placeholder arguments for that trait.
trait Trait<I> {
fn method(&self) {}
}
trait Trait2<'a, A, const B: u8, C = (), const D: u8 = 0> {
fn method2(&self) {}
}
fn foo<T>(value: T) {
//~^ SUGGESTION : Trait</* I */>
//~| SUGGESTION : Trait2</* 'a, A, B */>
value.method();
//~^ ERROR no method named `method` found for type parameter `T` in the current scope [E0599]
value.method2();
//~^ ERROR no method named `method2` found for type parameter `T` in the current scope [E0599]
}
fn bar(value: impl Copy) {
//~^ SUGGESTION + Trait</* I */>
//~| SUGGESTION + Trait2</* 'a, A, B */>
value.method();
//~^ ERROR no method named `method` found for type parameter `impl Copy` in the current scope [E0599]
value.method2();
//~^ ERROR no method named `method2` found for type parameter `impl Copy` in the current scope [E0599]
}
fn main() {}

View file

@ -0,0 +1,63 @@
error[E0599]: no method named `method` found for type parameter `T` in the current scope
--> $DIR/no-method-found-suggest-trait-args.rs:15:11
|
LL | fn foo<T>(value: T) {
| - method `method` not found for this type parameter
...
LL | value.method();
| ^^^^^^ method not found in `T`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
|
LL | fn foo<T: Trait</* I */>>(value: T) {
| ++++++++++++++++
error[E0599]: no method named `method2` found for type parameter `T` in the current scope
--> $DIR/no-method-found-suggest-trait-args.rs:17:11
|
LL | fn foo<T>(value: T) {
| - method `method2` not found for this type parameter
...
LL | value.method2();
| ^^^^^^^ method not found in `T`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `T` with it:
|
LL | fn foo<T: Trait2</* 'a, A, B */>>(value: T) {
| ++++++++++++++++++++++++
error[E0599]: no method named `method` found for type parameter `impl Copy` in the current scope
--> $DIR/no-method-found-suggest-trait-args.rs:24:11
|
LL | fn bar(value: impl Copy) {
| --------- method `method` not found for this type parameter
...
LL | value.method();
| ^^^^^^ method not found in `impl Copy`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `method`, perhaps you need to restrict type parameter `impl Copy` with it:
|
LL | fn bar(value: impl Copy + Trait</* I */>) {
| ++++++++++++++++
error[E0599]: no method named `method2` found for type parameter `impl Copy` in the current scope
--> $DIR/no-method-found-suggest-trait-args.rs:26:11
|
LL | fn bar(value: impl Copy) {
| --------- method `method2` not found for this type parameter
...
LL | value.method2();
| ^^^^^^^ method not found in `impl Copy`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `impl Copy` with it:
|
LL | fn bar(value: impl Copy + Trait2</* 'a, A, B */>) {
| ++++++++++++++++++++++++
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0599`.