Skip to content

Commit 4e59457

Browse files
authored
Rollup merge of #122651 - kornelski:flat-turbofish, r=spastorino,compiler-errors
Suggest `_` for missing generic arguments in turbofish The compiler may suggest unusable generic type names for missing generic arguments in an expression context: ```rust fn main() { (0..1).collect::<Vec>() } ``` > help: add missing generic argument > > (0..1).collect::<Vec<T>>() but `T` is not a valid name in this context, and this suggestion won't compile. I've changed it to use `_` inside method calls (turbofish), so it will suggest `(0..1).collect::<Vec<_>>()` which _may_ compile. It's possible that the suggested `_` will be ambiguous, but there is very extensive E0283 that will help resolve that, which is more helpful than a basic "cannot find type `T` in this scope" users would get otherwise. Out of caution to limit scope of the change I've limited it to just turbofish, but I suspect `_` could be the better choice in more cases. Perhaps in all expressions?
2 parents aa184c5 + 3bbbe3c commit 4e59457

File tree

3 files changed

+75
-8
lines changed

3 files changed

+75
-8
lines changed

compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
435435
&self,
436436
num_params_to_take: usize,
437437
) -> String {
438+
let is_in_a_method_call = self
439+
.tcx
440+
.hir()
441+
.parent_iter(self.path_segment.hir_id)
442+
.skip(1)
443+
.find_map(|(_, node)| match node {
444+
hir::Node::Expr(expr) => Some(expr),
445+
_ => None,
446+
})
447+
.is_some_and(|expr| {
448+
matches!(
449+
expr.kind,
450+
hir::ExprKind::MethodCall(hir::PathSegment { args: Some(_), .. }, ..)
451+
)
452+
});
453+
438454
let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
439455
let is_used_in_input = |def_id| {
440456
fn_sig.is_some_and(|fn_sig| {
@@ -453,14 +469,17 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
453469
.skip(self.params_offset + self.num_provided_type_or_const_args())
454470
.take(num_params_to_take)
455471
.map(|param| match param.kind {
456-
// This is being inferred from the item's inputs, no need to set it.
457-
ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
458-
"_".to_string()
472+
// If it's in method call (turbofish), it might be inferred from the expression (e.g. `.collect::<Vec<_>>()`)
473+
// If it is being inferred from the item's inputs, no need to set it.
474+
ty::GenericParamDefKind::Type { .. }
475+
if is_in_a_method_call || is_used_in_input(param.def_id) =>
476+
{
477+
"_"
459478
}
460-
_ => param.name.to_string(),
479+
_ => param.name.as_str(),
461480
})
462-
.collect::<Vec<_>>()
463-
.join(", ")
481+
.intersperse(", ")
482+
.collect()
464483
}
465484

466485
fn get_unbound_associated_types(&self) -> Vec<String> {

tests/ui/generics/generic-type-less-params-with-defaults.rs

+16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,23 @@ struct Heap;
55
struct Vec<T, A = Heap>(
66
marker::PhantomData<(T,A)>);
77

8+
struct HashMap<K, V, S = ()>(marker::PhantomData<(K,V,S)>);
9+
810
fn main() {
911
let _: Vec;
1012
//~^ ERROR missing generics for struct `Vec`
13+
//~| SUGGESTION <T>
14+
15+
let _x = (1..10).collect::<HashMap>();
16+
//~^ ERROR missing generics for struct `HashMap`
17+
//~| SUGGESTION <_, _>
18+
19+
().extend::<[(); 0]>({
20+
fn not_the_extend() {
21+
let _: Vec;
22+
//~^ ERROR missing generics for struct `Vec`
23+
//~| SUGGESTION <T>
24+
}
25+
[]
26+
});
1127
}

tests/ui/generics/generic-type-less-params-with-defaults.stderr

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0107]: missing generics for struct `Vec`
2-
--> $DIR/generic-type-less-params-with-defaults.rs:9:12
2+
--> $DIR/generic-type-less-params-with-defaults.rs:11:12
33
|
44
LL | let _: Vec;
55
| ^^^ expected at least 1 generic argument
@@ -14,6 +14,38 @@ help: add missing generic argument
1414
LL | let _: Vec<T>;
1515
| +++
1616

17-
error: aborting due to 1 previous error
17+
error[E0107]: missing generics for struct `HashMap`
18+
--> $DIR/generic-type-less-params-with-defaults.rs:15:32
19+
|
20+
LL | let _x = (1..10).collect::<HashMap>();
21+
| ^^^^^^^ expected at least 2 generic arguments
22+
|
23+
note: struct defined here, with at least 2 generic parameters: `K`, `V`
24+
--> $DIR/generic-type-less-params-with-defaults.rs:8:8
25+
|
26+
LL | struct HashMap<K, V, S = ()>(marker::PhantomData<(K,V,S)>);
27+
| ^^^^^^^ - -
28+
help: add missing generic arguments
29+
|
30+
LL | let _x = (1..10).collect::<HashMap<_, _>>();
31+
| ++++++
32+
33+
error[E0107]: missing generics for struct `Vec`
34+
--> $DIR/generic-type-less-params-with-defaults.rs:21:20
35+
|
36+
LL | let _: Vec;
37+
| ^^^ expected at least 1 generic argument
38+
|
39+
note: struct defined here, with at least 1 generic parameter: `T`
40+
--> $DIR/generic-type-less-params-with-defaults.rs:5:8
41+
|
42+
LL | struct Vec<T, A = Heap>(
43+
| ^^^ -
44+
help: add missing generic argument
45+
|
46+
LL | let _: Vec<T>;
47+
| +++
48+
49+
error: aborting due to 3 previous errors
1850

1951
For more information about this error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)