Skip to content

Commit bb83e15

Browse files
committed
Suggest specifying local binding types
1 parent 401560c commit bb83e15

28 files changed

+289
-124
lines changed

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
449449
error_code,
450450
);
451451

452-
let suffix = match local_visitor.found_node_ty {
452+
let (suffix, sugg_ty) = match local_visitor.found_node_ty {
453453
Some(ty) if ty.is_closure() => {
454454
let substs =
455455
if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
@@ -484,20 +484,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
484484
// This suggestion is incomplete, as the user will get further type inference
485485
// errors due to the `_` placeholders and the introduction of `Box`, but it does
486486
// nudge them in the right direction.
487-
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
487+
(
488+
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret),
489+
format!("Box<dyn Fn({}) -> {}>", args, ret),
490+
)
488491
}
489492
Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
490493
let ty = ty_to_string(ty);
491-
format!("the explicit type `{}`, with the type parameters specified", ty)
494+
(
495+
format!("the explicit type `{}`, with the type parameters specified", ty),
496+
ty.to_string(),
497+
)
492498
}
493499
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
494500
let ty = ty_to_string(ty);
495-
format!(
496-
"the explicit type `{}`, where the type parameter `{}` is specified",
497-
ty, arg_data.name,
501+
(
502+
format!(
503+
"the explicit type `{}`, where the type parameter `{}` is specified",
504+
ty, arg_data.name,
505+
),
506+
ty.to_string(),
498507
)
499508
}
500-
_ => "a type".to_string(),
509+
_ if turbofish_suggestions.len() == 1 => (
510+
format!("the explicit type `{}`", turbofish_suggestions[0]),
511+
turbofish_suggestions[0].clone(),
512+
),
513+
_ => ("a type".to_string(), "Type".to_string()),
501514
};
502515

503516
if let Some(e) = local_visitor.found_exact_method_call {
@@ -552,18 +565,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
552565
format!("consider giving this closure parameter {}", suffix),
553566
);
554567
} else if let Some(pattern) = local_visitor.found_local_pattern {
555-
let msg = if let Some(simple_ident) = pattern.simple_ident() {
556-
match pattern.span.desugaring_kind() {
557-
None => format!("consider giving `{}` {}", simple_ident, suffix),
558-
Some(DesugaringKind::ForLoop(_)) => {
559-
"the element type for this iterator is not specified".to_string()
560-
}
561-
_ => format!("this needs {}", suffix),
562-
}
568+
if let (hir::Node::Local(local), None) = (
569+
self.tcx.hir().get(self.tcx.hir().get_parent_node(pattern.hir_id)),
570+
pattern.span.desugaring_kind(),
571+
) {
572+
let (span, prefix) = match local.ty {
573+
Some(ty) => (ty.span, ""),
574+
None => (local.pat.span.shrink_to_hi(), ": "),
575+
};
576+
let msg = format!("consider giving this binding {}", suffix);
577+
match &turbofish_suggestions[..] {
578+
[] => err.span_suggestion_verbose(
579+
span,
580+
&msg,
581+
format!("{}{}", prefix, sugg_ty),
582+
Applicability::HasPlaceholders,
583+
),
584+
[ty] => err.span_suggestion_verbose(
585+
span,
586+
&msg,
587+
format!("{}{}", prefix, ty),
588+
Applicability::MachineApplicable,
589+
),
590+
_ => err.span_suggestions(
591+
span,
592+
&msg,
593+
turbofish_suggestions.into_iter().map(|ty| format!("{}{}", prefix, ty)),
594+
Applicability::MaybeIncorrect,
595+
),
596+
};
563597
} else {
564-
format!("consider giving this pattern {}", suffix)
565-
};
566-
err.span_label(pattern.span, msg);
598+
let msg = if let Some(simple_ident) = pattern.simple_ident() {
599+
match pattern.span.desugaring_kind() {
600+
None => format!("consider giving `{}` {}", simple_ident, suffix),
601+
Some(DesugaringKind::ForLoop(_)) => {
602+
"the element type for this iterator is not specified".to_string()
603+
}
604+
_ => format!("this needs {}", suffix),
605+
}
606+
} else {
607+
format!("consider giving this pattern {}", suffix)
608+
};
609+
err.span_label(pattern.span, msg);
610+
}
567611
} else if let Some(e) = local_visitor.found_method_call {
568612
if let ExprKind::MethodCall(segment, ..) = &e.kind {
569613
// Suggest specifying type params or point out the return type of the call:

src/test/ui/array-slice-vec/infer_array_len.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ error[E0282]: type annotations needed
22
--> $DIR/infer_array_len.rs:19:9
33
|
44
LL | let [_, _] = a.into();
5-
| ^^^^^^ consider giving this pattern a type
5+
| ^^^^^^ cannot infer type
66
|
77
= note: type must be known at this point
8+
help: consider giving this binding a type
9+
|
10+
LL | let [_, _]: Type = a.into();
11+
| ^^^^^^
812

913
error: aborting due to previous error
1014

src/test/ui/error-codes/E0282.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
22
--> $DIR/E0282.rs:2:9
33
|
44
LL | let x = "hello".chars().rev().collect();
5-
| ^ consider giving `x` a type
5+
| ^ cannot infer type
6+
|
7+
help: consider giving this binding a type
8+
|
9+
LL | let x: Type = "hello".chars().rev().collect();
10+
| ^^^^^^
611

712
error: aborting due to previous error
813

src/test/ui/error-codes/E0661.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ error[E0282]: type annotations needed
88
--> $DIR/E0661.rs:6:9
99
|
1010
LL | let a;
11-
| ^ consider giving `a` a type
11+
| ^ cannot infer type
12+
|
13+
help: consider giving this binding a type
14+
|
15+
LL | let a: Type;
16+
| ^^^^^^
1217

1318
error: aborting due to 2 previous errors
1419

src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ LL | #![feature(impl_trait_in_bindings)]
1010
error[E0282]: type annotations needed for `impl Future`
1111
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
1212
|
13-
LL | let fut = async {
14-
| --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
1513
LL | make_unit()?;
1614
| ^ cannot infer type
15+
|
16+
help: consider giving this binding the explicit type `impl Future`, with the type parameters specified
17+
|
18+
LL | let fut: impl Future = async {
19+
| ^^^^^^^^^^^^^
1720

1821
error: aborting due to previous error; 1 warning emitted
1922

src/test/ui/inference/cannot-infer-async.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
error[E0282]: type annotations needed
22
--> $DIR/cannot-infer-async.rs:11:20
33
|
4-
LL | let fut = async {
5-
| --- consider giving `fut` a type
64
LL | make_unit()?;
75
| ^ cannot infer type
6+
|
7+
help: consider giving this binding a type
8+
|
9+
LL | let fut: Type = async {
10+
| ^^^^^^
811

912
error: aborting due to previous error
1013

src/test/ui/issues/issue-12187-1.stderr

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0282]: type annotations needed for `&T`
22
--> $DIR/issue-12187-1.rs:6:10
33
|
44
LL | let &v = new();
5-
| -^
6-
| ||
7-
| |cannot infer type
8-
| consider giving this pattern the explicit type `&T`, with the type parameters specified
5+
| ^ cannot infer type
6+
|
7+
help: consider giving this binding the explicit type `&T`, with the type parameters specified
8+
|
9+
LL | let &v: &T = new();
10+
| ^^^^
911

1012
error: aborting due to previous error
1113

src/test/ui/issues/issue-12187-2.stderr

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0282]: type annotations needed for `&T`
22
--> $DIR/issue-12187-2.rs:6:10
33
|
44
LL | let &v = new();
5-
| -^
6-
| ||
7-
| |cannot infer type
8-
| consider giving this pattern the explicit type `&T`, with the type parameters specified
5+
| ^ cannot infer type
6+
|
7+
help: consider giving this binding the explicit type `&T`, with the type parameters specified
8+
|
9+
LL | let &v: &T = new();
10+
| ^^^^
911

1012
error: aborting due to previous error
1113

src/test/ui/issues/issue-17551.stderr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0282]: type annotations needed for `B<T>`
22
--> $DIR/issue-17551.rs:6:15
33
|
44
LL | let foo = B(marker::PhantomData);
5-
| --- ^ cannot infer type for type parameter `T` declared on the struct `B`
6-
| |
7-
| consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
5+
| ^ cannot infer type for type parameter `T` declared on the struct `B`
6+
|
7+
help: consider giving this binding the explicit type `B<T>`, where the type parameter `T` is specified
8+
|
9+
LL | let foo: B<T> = B(marker::PhantomData);
10+
| ^^^^^^
811

912
error: aborting due to previous error
1013

src/test/ui/issues/issue-18159.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
22
--> $DIR/issue-18159.rs:2:9
33
|
44
LL | let x;
5-
| ^ consider giving `x` a type
5+
| ^ cannot infer type
6+
|
7+
help: consider giving this binding a type
8+
|
9+
LL | let x: Type;
10+
| ^^^^^^
611

712
error: aborting due to previous error
813

0 commit comments

Comments
 (0)