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(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)]
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
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