Skip to content

Commit 2afb931

Browse files
committed
Provide placeholder generic arguments for traits in "no method found for type parameter" suggestions
1 parent 7c7bb7d commit 2afb931

File tree

4 files changed

+135
-21
lines changed

4 files changed

+135
-21
lines changed

Diff for: compiler/rustc_hir_typeck/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![feature(array_windows)]
55
#![feature(box_patterns)]
66
#![feature(if_let_guard)]
7+
#![feature(iter_intersperse)]
78
#![feature(let_chains)]
89
#![feature(never_type)]
910
#![feature(try_blocks)]

Diff for: compiler/rustc_hir_typeck/src/method/suggest.rs

+41-21
Original file line numberDiff line numberDiff line change
@@ -3872,22 +3872,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38723872
param.name.ident(),
38733873
));
38743874
let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
3875+
let mut applicability = Applicability::MaybeIncorrect;
3876+
// Format the path of each suggested candidate, providing placeholders
3877+
// for any generic arguments without defaults.
3878+
let candidate_strs: Vec<String> = candidates
3879+
.iter()
3880+
.map(|cand| {
3881+
use ty::GenericParamDefKind::{Const, Lifetime, Type};
3882+
let cand_path = self.tcx.def_path_str(cand.def_id);
3883+
let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
3884+
let cand_args: String = cand_params
3885+
.iter()
3886+
.skip(1)
3887+
.filter_map(|param| match param.kind {
3888+
Lifetime => Some("'_"),
3889+
Type { has_default: true, .. }
3890+
| Const { has_default: true, .. } => None,
3891+
// in keeping with suggestions for missing generic args,
3892+
// use their names from the trait definition as placeholders
3893+
Type { .. } | Const { .. } => Some(param.name.as_str()),
3894+
})
3895+
.intersperse(", ")
3896+
.collect();
3897+
if cand_args.is_empty() {
3898+
cand_path
3899+
} else {
3900+
applicability = Applicability::HasPlaceholders;
3901+
format!("{cand_path}<{cand_args}>")
3902+
}
3903+
})
3904+
.collect();
3905+
38753906
if rcvr_ty.is_ref()
38763907
&& param.is_impl_trait()
38773908
&& let Some((bounds_span, _)) = bounds_span
38783909
{
38793910
err.multipart_suggestions(
38803911
msg,
3881-
candidates.iter().map(|t| {
3912+
candidate_strs.iter().map(|cand| {
38823913
vec![
38833914
(param.span.shrink_to_lo(), "(".to_string()),
3884-
(
3885-
bounds_span,
3886-
format!(" + {})", self.tcx.def_path_str(t.def_id)),
3887-
),
3915+
(bounds_span, format!(" + {cand})")),
38883916
]
38893917
}),
3890-
Applicability::MaybeIncorrect,
3918+
applicability,
38913919
);
38923920
return;
38933921
}
@@ -3903,16 +3931,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39033931
(param.span.shrink_to_hi(), Introducer::Colon, None)
39043932
};
39053933

3906-
let all_suggs = candidates.iter().map(|cand| {
3907-
let suggestion = format!(
3908-
"{} {}",
3909-
match introducer {
3910-
Introducer::Plus => " +",
3911-
Introducer::Colon => ":",
3912-
Introducer::Nothing => "",
3913-
},
3914-
self.tcx.def_path_str(cand.def_id)
3915-
);
3934+
let all_suggs = candidate_strs.iter().map(|cand| {
3935+
let suggestion = format!("{} {cand}", match introducer {
3936+
Introducer::Plus => " +",
3937+
Introducer::Colon => ":",
3938+
Introducer::Nothing => "",
3939+
},);
39163940

39173941
let mut suggs = vec![];
39183942

@@ -3926,11 +3950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39263950
suggs
39273951
});
39283952

3929-
err.multipart_suggestions(
3930-
msg,
3931-
all_suggs,
3932-
Applicability::MaybeIncorrect,
3933-
);
3953+
err.multipart_suggestions(msg, all_suggs, applicability);
39343954

39353955
return;
39363956
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// Tests that suggestions to add trait bounds that would enable using a method include appropriate
2+
/// placeholder arguments for that trait.
3+
4+
trait Trait<I> {
5+
fn method(&self) {}
6+
}
7+
8+
trait Trait2<'a, A, const B: u8, C = (), const D: u8 = 0> {
9+
fn method2(&self) {}
10+
}
11+
12+
fn foo<T>(value: T) {
13+
//~^ SUGGESTION : Trait<I>
14+
//~| SUGGESTION : Trait2<'_, A, B>
15+
value.method();
16+
//~^ ERROR no method named `method` found for type parameter `T` in the current scope [E0599]
17+
value.method2();
18+
//~^ ERROR no method named `method2` found for type parameter `T` in the current scope [E0599]
19+
}
20+
21+
fn bar(value: impl Copy) {
22+
//~^ SUGGESTION + Trait<I>
23+
//~| SUGGESTION + Trait2<'_, A, B>
24+
value.method();
25+
//~^ ERROR no method named `method` found for type parameter `impl Copy` in the current scope [E0599]
26+
value.method2();
27+
//~^ ERROR no method named `method2` found for type parameter `impl Copy` in the current scope [E0599]
28+
}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0599]: no method named `method` found for type parameter `T` in the current scope
2+
--> $DIR/no-method-found-suggest-trait-args.rs:15:11
3+
|
4+
LL | fn foo<T>(value: T) {
5+
| - method `method` not found for this type parameter
6+
...
7+
LL | value.method();
8+
| ^^^^^^ method not found in `T`
9+
|
10+
= help: items from traits can only be used if the type parameter is bounded by the trait
11+
help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
12+
|
13+
LL | fn foo<T: Trait<I>>(value: T) {
14+
| ++++++++++
15+
16+
error[E0599]: no method named `method2` found for type parameter `T` in the current scope
17+
--> $DIR/no-method-found-suggest-trait-args.rs:17:11
18+
|
19+
LL | fn foo<T>(value: T) {
20+
| - method `method2` not found for this type parameter
21+
...
22+
LL | value.method2();
23+
| ^^^^^^^ method not found in `T`
24+
|
25+
= help: items from traits can only be used if the type parameter is bounded by the trait
26+
help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `T` with it:
27+
|
28+
LL | fn foo<T: Trait2<'_, A, B>>(value: T) {
29+
| ++++++++++++++++++
30+
31+
error[E0599]: no method named `method` found for type parameter `impl Copy` in the current scope
32+
--> $DIR/no-method-found-suggest-trait-args.rs:24:11
33+
|
34+
LL | fn bar(value: impl Copy) {
35+
| --------- method `method` not found for this type parameter
36+
...
37+
LL | value.method();
38+
| ^^^^^^ method not found in `impl Copy`
39+
|
40+
= help: items from traits can only be used if the type parameter is bounded by the trait
41+
help: the following trait defines an item `method`, perhaps you need to restrict type parameter `impl Copy` with it:
42+
|
43+
LL | fn bar(value: impl Copy + Trait<I>) {
44+
| ++++++++++
45+
46+
error[E0599]: no method named `method2` found for type parameter `impl Copy` in the current scope
47+
--> $DIR/no-method-found-suggest-trait-args.rs:26:11
48+
|
49+
LL | fn bar(value: impl Copy) {
50+
| --------- method `method2` not found for this type parameter
51+
...
52+
LL | value.method2();
53+
| ^^^^^^^ method not found in `impl Copy`
54+
|
55+
= help: items from traits can only be used if the type parameter is bounded by the trait
56+
help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `impl Copy` with it:
57+
|
58+
LL | fn bar(value: impl Copy + Trait2<'_, A, B>) {
59+
| ++++++++++++++++++
60+
61+
error: aborting due to 4 previous errors
62+
63+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)