Provide placeholder generic arguments for traits in "no method found for type parameter" suggestions
This commit is contained in:
parent
de27914e8e
commit
02add7d0fb
4 changed files with 137 additions and 21 deletions
|
@ -4,6 +4,7 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(try_blocks)]
|
||||
|
|
|
@ -3874,22 +3874,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
param.name.ident(),
|
||||
));
|
||||
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()
|
||||
&& param.is_impl_trait()
|
||||
&& let Some((bounds_span, _)) = bounds_span
|
||||
{
|
||||
err.multipart_suggestions(
|
||||
msg,
|
||||
candidates.iter().map(|t| {
|
||||
candidate_strs.iter().map(|cand| {
|
||||
vec![
|
||||
(param.span.shrink_to_lo(), "(".to_string()),
|
||||
(
|
||||
bounds_span,
|
||||
format!(" + {})", self.tcx.def_path_str(t.def_id)),
|
||||
),
|
||||
(bounds_span, format!(" + {cand})")),
|
||||
]
|
||||
}),
|
||||
Applicability::MaybeIncorrect,
|
||||
applicability,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -3905,16 +3935,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(param.span.shrink_to_hi(), Introducer::Colon, None)
|
||||
};
|
||||
|
||||
let all_suggs = candidates.iter().map(|cand| {
|
||||
let suggestion = format!(
|
||||
"{} {}",
|
||||
match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},
|
||||
self.tcx.def_path_str(cand.def_id)
|
||||
);
|
||||
let all_suggs = candidate_strs.iter().map(|cand| {
|
||||
let suggestion = format!("{} {cand}", match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},);
|
||||
|
||||
let mut suggs = vec![];
|
||||
|
||||
|
@ -3928,11 +3954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
suggs
|
||||
});
|
||||
|
||||
err.multipart_suggestions(
|
||||
msg,
|
||||
all_suggs,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.multipart_suggestions(msg, all_suggs, applicability);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
30
tests/ui/suggestions/no-method-found-suggest-trait-args.rs
Normal file
30
tests/ui/suggestions/no-method-found-suggest-trait-args.rs
Normal 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() {}
|
|
@ -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`.
|
Loading…
Add table
Reference in a new issue