diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-05-30 10:19:58 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-05-31 18:33:59 -0700 |
| commit | 8bb094dac596a98cd3347979984834fe67bf3fcb (patch) | |
| tree | 47aaf9ba899ba93541dc261700c641d90ba62b33 | |
| parent | 7840a0b753a065a41999f1fb6028f67d33e3fdd5 (diff) | |
| download | rust-8bb094dac596a98cd3347979984834fe67bf3fcb.tar.gz rust-8bb094dac596a98cd3347979984834fe67bf3fcb.zip | |
Add more detail to type inference error
When encountering code where type inference fails, add more actionable
information:
```
fn main() {
let foo = Vec::new();
}
```
```
error[E0282]: type annotations needed for `std::vec::Vec<_>`
--> $DIR/vector-no-ann.rs:2:16
|
LL | let foo = Vec::new();
| --- ^^^^^^^^ cannot infer type for `T`
| |
| consider giving `foo` the type `std::vec::Vec<_>` with the type parameter `T` specified
```
We still need to modify type printing to optionally accept a
`TypeVariableTable` in order to properly print `std::vec::Vec<T>`.
CC #25633.
19 files changed, 82 insertions, 42 deletions
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 972ffbe1820..173f916c282 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -15,17 +15,18 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { hir_map: &'a hir::map::Map<'gcx>, found_local_pattern: Option<&'gcx Pat>, found_arg_pattern: Option<&'gcx Pat>, + found_ty: Option<Ty<'tcx>>, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn node_matches_type(&mut self, hir_id: HirId) -> bool { + fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { tables.borrow().node_type_opt(hir_id) }); match ty_opt { Some(ty) => { let ty = self.infcx.resolve_vars_if_possible(&ty); - ty.walk().any(|inner_ty| { + if ty.walk().any(|inner_ty| { inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { self.infcx @@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { } _ => false, } - }) + }) { + Some(ty) + } else { + None + } } - None => false, + None => None, } } } @@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { } fn visit_local(&mut self, local: &'gcx Local) { - if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) { + if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) { self.found_local_pattern = Some(&*local.pat); + self.found_ty = Some(ty); } intravisit::walk_local(self, local); } fn visit_body(&mut self, body: &'gcx Body) { for argument in &body.arguments { - if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) { + if let (None, Some(ty)) = ( + self.found_arg_pattern, + self.node_matches_type(argument.hir_id), + ) { self.found_arg_pattern = Some(&*argument.pat); + self.found_ty = Some(ty); } } intravisit::walk_body(self, body); @@ -106,6 +116,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir(), found_local_pattern: None, found_arg_pattern: None, + found_ty: None, }; if let Some(body_id) = body_id { @@ -113,6 +124,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { local_visitor.visit_expr(expr); } + let ty_msg = match local_visitor.found_ty { + Some(ty) if &ty.to_string() != "_" => format!(" for `{}`", ty), + _ => String::new(), + }; if let Some(pattern) = local_visitor.found_arg_pattern { err_span = pattern.span; // We don't want to show the default label for closures. @@ -131,13 +146,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // ^ consider giving this closure parameter a type // ``` labels.clear(); - labels.push( - (pattern.span, "consider giving this closure parameter a type".to_owned())); + labels.push((pattern.span, format!( + "consider giving this closure parameter {}", + match local_visitor.found_ty { + Some(ty) if &ty.to_string() != "_" => format!( + "the type `{}` with the type parameter `{}` specified", + ty, + name, + ), + _ => "a type".to_owned(), + }, + ))); } else if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.compiler_desugaring_kind() { - None => labels.push((pattern.span, - format!("consider giving `{}` a type", simple_ident))), + None => labels.push(( + pattern.span, + format!( + "consider giving `{}` {}", + simple_ident, + match local_visitor.found_ty { + Some(ty) if &ty.to_string() != "_" => format!( + "the type `{}` with the type parameter `{}` specified", + ty, + name, + ), + _ => "a type".to_owned(), + }, + ), + )), Some(CompilerDesugaringKind::ForLoop) => labels.push(( pattern.span, "the element type for this iterator is not specified".to_owned(), @@ -147,12 +184,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { labels.push((pattern.span, "consider giving the pattern a type".to_owned())); } - } + }; - let mut err = struct_span_err!(self.tcx.sess, - err_span, - E0282, - "type annotations needed"); + let mut err = struct_span_err!( + self.tcx.sess, + err_span, + E0282, + "type annotations needed{}", + ty_msg, + ); for (target_span, label_message) in labels { err.span_label(target_span, label_message); diff --git a/src/test/ui/issues/issue-12187-1.rs b/src/test/ui/issues/issue-12187-1.rs index 37ff468e032..86128ed94bd 100644 --- a/src/test/ui/issues/issue-12187-1.rs +++ b/src/test/ui/issues/issue-12187-1.rs @@ -4,5 +4,5 @@ fn new<T>() -> &'static T { fn main() { let &v = new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-12187-1.stderr b/src/test/ui/issues/issue-12187-1.stderr index f8df4f82e7e..77aa736873b 100644 --- a/src/test/ui/issues/issue-12187-1.stderr +++ b/src/test/ui/issues/issue-12187-1.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&_` --> $DIR/issue-12187-1.rs:6:10 | LL | let &v = new(); diff --git a/src/test/ui/issues/issue-12187-2.rs b/src/test/ui/issues/issue-12187-2.rs index a1cdb849779..080a6206be7 100644 --- a/src/test/ui/issues/issue-12187-2.rs +++ b/src/test/ui/issues/issue-12187-2.rs @@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T { fn main() { let &v = new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-12187-2.stderr b/src/test/ui/issues/issue-12187-2.stderr index c40ae0461ec..4953c2b11b5 100644 --- a/src/test/ui/issues/issue-12187-2.stderr +++ b/src/test/ui/issues/issue-12187-2.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&_` --> $DIR/issue-12187-2.rs:6:10 | LL | let &v = new(); diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr index 40e7727752b..3e99d307b3b 100644 --- a/src/test/ui/issues/issue-17551.stderr +++ b/src/test/ui/issues/issue-17551.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `B<_>` --> $DIR/issue-17551.rs:6:15 | LL | let foo = B(marker::PhantomData); | --- ^ cannot infer type for `T` | | - | consider giving `foo` a type + | consider giving `foo` the type `B<_>` with the type parameter `T` specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr index 5665f5893f4..c6c3f32dfe7 100644 --- a/src/test/ui/issues/issue-20261.stderr +++ b/src/test/ui/issues/issue-20261.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&(_,)` --> $DIR/issue-20261.rs:4:11 | LL | for (ref i,) in [].iter() { diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr index aab90a9d440..2ce77576404 100644 --- a/src/test/ui/issues/issue-23046.stderr +++ b/src/test/ui/issues/issue-23046.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `Expr<'_, _>` --> $DIR/issue-23046.rs:17:15 | LL | let ex = |x| { - | ^ consider giving this closure parameter a type + | ^ consider giving this closure parameter the type `Expr<'_, _>` with the type parameter `VAR` specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index 3ad6a2569be..3b2c3bfe4ff 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `(std::sync::mpsc::Sender<Foo<_>>, std::sync::mpsc::Receiver<Foo<_>>)` --> $DIR/issue-25368.rs:11:17 | LL | let (tx, rx) = channel(); diff --git a/src/test/ui/issues/issue-7813.stderr b/src/test/ui/issues/issue-7813.stderr index 45b9c915885..8e2a69dd9e3 100644 --- a/src/test/ui/issues/issue-7813.stderr +++ b/src/test/ui/issues/issue-7813.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&[_; 0]` --> $DIR/issue-7813.rs:2:13 | LL | let v = &[]; | - ^^^ cannot infer type | | - | consider giving `v` a type + | consider giving `v` the type `&[_; 0]` with the type parameter `_` specified error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs index 590e98dc353..e33f23c64db 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs @@ -22,7 +22,7 @@ impl Foo for Vec<isize> { fn m1() { // we couldn't infer the type of the vector just based on calling foo()... let mut x = Vec::new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed x.foo(); } diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 063a4865b19..bae675526bd 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec<_>` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17 | LL | let mut x = Vec::new(); | ----- ^^^^^^^^ cannot infer type for `T` | | - | consider giving `x` a type + | consider giving `x` the type `std::vec::Vec<_>` with the type parameter `T` specified error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 8923de5705b..9b0d56e38b7 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::option::Option<_>` --> $DIR/issue-42234-unknown-receiver-type.rs:7:5 | LL | let x: Option<_> = None; - | - consider giving `x` a type + | - consider giving `x` the type `std::option::Option<_>` with the type parameter `T` specified LL | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^^^^^ cannot infer type for `T` | diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr index 17be67c6c3a..115808b3b3e 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `[_; 0]` --> $DIR/cannot_infer_local_or_array.rs:2:13 | LL | let x = []; | - ^^ cannot infer type | | - | consider giving `x` a type + | consider giving `x` the type `[_; 0]` with the type parameter `_` specified error: aborting due to previous error diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr index 8215947d49c..49b4330b51e 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec<_>` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; | - ^^^^^^ cannot infer type for `T` | | - | consider giving `x` a type + | consider giving `x` the type `std::vec::Vec<_>` with the type parameter `T` specified | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr index 1065d49c26b..57eb185a36a 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `(std::vec::Vec<_>,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index bd58e241f0c..d0d8aed0cb8 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::option::Option<_>` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32 | LL | let mut closure0 = None; - | ------------ consider giving `closure0` a type + | ------------ consider giving `closure0` the type `std::option::Option<_>` with the type parameter `_` specified ... LL | return c(); | ^^^ cannot infer type diff --git a/src/test/ui/vector-no-ann.rs b/src/test/ui/vector-no-ann.rs index 200364a5d93..1f11d9c8dff 100644 --- a/src/test/ui/vector-no-ann.rs +++ b/src/test/ui/vector-no-ann.rs @@ -1,4 +1,4 @@ fn main() { let _foo = Vec::new(); - //~^ ERROR type annotations needed [E0282] + //~^ ERROR type annotations needed } diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 01b569f97f9..6aa925e0715 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `std::vec::Vec<_>` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); | ---- ^^^^^^^^ cannot infer type for `T` | | - | consider giving `_foo` a type + | consider giving `_foo` the type `std::vec::Vec<_>` with the type parameter `T` specified error: aborting due to previous error |
