Skip to content

Commit

Permalink
Add more detail to type inference error
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
estebank committed Jun 1, 2019
1 parent 7840a0b commit 8bb094d
Show file tree
Hide file tree
Showing 19 changed files with 82 additions and 42 deletions.
70 changes: 55 additions & 15 deletions src/librustc/infer/error_reporting/need_type_info.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
hir_map: &'a hir::map::Map<'gcx>, hir_map: &'a hir::map::Map<'gcx>,
found_local_pattern: Option<&'gcx Pat>, found_local_pattern: Option<&'gcx Pat>,
found_arg_pattern: Option<&'gcx Pat>, found_arg_pattern: Option<&'gcx Pat>,
found_ty: Option<Ty<'tcx>>,
} }


impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, '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| { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_type_opt(hir_id) tables.borrow().node_type_opt(hir_id)
}); });
match ty_opt { match ty_opt {
Some(ty) => { Some(ty) => {
let ty = self.infcx.resolve_vars_if_possible(&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) { inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
self.infcx self.infcx
Expand All @@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
} }
_ => false, _ => false,
} }
}) }) {
Some(ty)
} else {
None
}
} }
None => false, None => None,
} }
} }
} }
Expand All @@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
} }


fn visit_local(&mut self, local: &'gcx Local) { 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_local_pattern = Some(&*local.pat);
self.found_ty = Some(ty);
} }
intravisit::walk_local(self, local); intravisit::walk_local(self, local);
} }


fn visit_body(&mut self, body: &'gcx Body) { fn visit_body(&mut self, body: &'gcx Body) {
for argument in &body.arguments { 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_arg_pattern = Some(&*argument.pat);
self.found_ty = Some(ty);
} }
} }
intravisit::walk_body(self, body); intravisit::walk_body(self, body);
Expand Down Expand Up @@ -106,13 +116,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
hir_map: &self.tcx.hir(), hir_map: &self.tcx.hir(),
found_local_pattern: None, found_local_pattern: None,
found_arg_pattern: None, found_arg_pattern: None,
found_ty: None,
}; };


if let Some(body_id) = body_id { if let Some(body_id) = body_id {
let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id); let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
local_visitor.visit_expr(expr); 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 { if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span; err_span = pattern.span;
// We don't want to show the default label for closures. // We don't want to show the default label for closures.
Expand All @@ -131,13 +146,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// ^ consider giving this closure parameter a type // ^ consider giving this closure parameter a type
// ``` // ```
labels.clear(); labels.clear();
labels.push( labels.push((pattern.span, format!(
(pattern.span, "consider giving this closure parameter a type".to_owned())); "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 { } else if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_ident) = pattern.simple_ident() { if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.compiler_desugaring_kind() { match pattern.span.compiler_desugaring_kind() {
None => labels.push((pattern.span, None => labels.push((
format!("consider giving `{}` a type", simple_ident))), 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(( Some(CompilerDesugaringKind::ForLoop) => labels.push((
pattern.span, pattern.span,
"the element type for this iterator is not specified".to_owned(), "the element type for this iterator is not specified".to_owned(),
Expand All @@ -147,12 +184,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} else { } else {
labels.push((pattern.span, "consider giving the pattern a type".to_owned())); labels.push((pattern.span, "consider giving the pattern a type".to_owned()));
} }
} };


let mut err = struct_span_err!(self.tcx.sess, let mut err = struct_span_err!(
err_span, self.tcx.sess,
E0282, err_span,
"type annotations needed"); E0282,
"type annotations needed{}",
ty_msg,
);


for (target_span, label_message) in labels { for (target_span, label_message) in labels {
err.span_label(target_span, label_message); err.span_label(target_span, label_message);
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-1.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ fn new<T>() -> &'static T {


fn main() { fn main() {
let &v = new(); let &v = new();
//~^ ERROR type annotations needed [E0282] //~^ ERROR type annotations needed
} }
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-1.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `&_`
--> $DIR/issue-12187-1.rs:6:10 --> $DIR/issue-12187-1.rs:6:10
| |
LL | let &v = new(); LL | let &v = new();
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-2.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T {


fn main() { fn main() {
let &v = new(); let &v = new();
//~^ ERROR type annotations needed [E0282] //~^ ERROR type annotations needed
} }
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-12187-2.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `&_`
--> $DIR/issue-12187-2.rs:6:10 --> $DIR/issue-12187-2.rs:6:10
| |
LL | let &v = new(); LL | let &v = new();
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-17551.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `B<_>`
--> $DIR/issue-17551.rs:6:15 --> $DIR/issue-17551.rs:6:15
| |
LL | let foo = B(marker::PhantomData); LL | let foo = B(marker::PhantomData);
| --- ^ cannot infer type for `T` | --- ^ 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 error: aborting due to previous error


Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-20261.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `&(_,)`
--> $DIR/issue-20261.rs:4:11 --> $DIR/issue-20261.rs:4:11
| |
LL | for (ref i,) in [].iter() { LL | for (ref i,) in [].iter() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-23046.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `Expr<'_, _>`
--> $DIR/issue-23046.rs:17:15 --> $DIR/issue-23046.rs:17:15
| |
LL | let ex = |x| { 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 error: aborting due to previous error


Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-25368.stderr
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/issue-25368.rs:11:17
| |
LL | let (tx, rx) = channel(); LL | let (tx, rx) = channel();
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-7813.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed error[E0282]: type annotations needed for `&[_; 0]`
--> $DIR/issue-7813.rs:2:13 --> $DIR/issue-7813.rs:2:13
| |
LL | let v = &[]; LL | let v = &[];
| - ^^^ cannot infer type | - ^^^ 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 error: aborting due to previous error


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl Foo for Vec<isize> {
fn m1() { fn m1() {
// we couldn't infer the type of the vector just based on calling foo()... // we couldn't infer the type of the vector just based on calling foo()...
let mut x = Vec::new(); let mut x = Vec::new();
//~^ ERROR type annotations needed [E0282] //~^ ERROR type annotations needed
x.foo(); x.foo();
} }


Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
| |
LL | let mut x = Vec::new(); LL | let mut x = Vec::new();
| ----- ^^^^^^^^ cannot infer type for `T` | ----- ^^^^^^^^ 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 error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/span/issue-42234-unknown-receiver-type.stderr
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/issue-42234-unknown-receiver-type.rs:7:5
| |
LL | let x: Option<_> = None; 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(); LL | x.unwrap().method_that_could_exist_on_some_type();
| ^^^^^^^^^^ cannot infer type for `T` | ^^^^^^^^^^ cannot infer type for `T`
| |
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/cannot_infer_local_or_array.rs:2:13
| |
LL | let x = []; LL | let x = [];
| - ^^ cannot infer type | - ^^ 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 error: aborting due to previous error


Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/cannot_infer_local_or_vec.rs:2:13
| |
LL | let x = vec![]; LL | let x = vec![];
| - ^^^^^^ cannot infer type for `T` | - ^^^^^^ 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) = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)


Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
| |
LL | let (x, ) = (vec![], ); LL | let (x, ) = (vec![], );
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
| |
LL | let mut closure0 = None; 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(); LL | return c();
| ^^^ cannot infer type | ^^^ cannot infer type
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/vector-no-ann.rs
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,4 @@
fn main() { fn main() {
let _foo = Vec::new(); let _foo = Vec::new();
//~^ ERROR type annotations needed [E0282] //~^ ERROR type annotations needed
} }
4 changes: 2 additions & 2 deletions src/test/ui/vector-no-ann.stderr
Original file line number Original file line Diff line number Diff line change
@@ -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 --> $DIR/vector-no-ann.rs:2:16
| |
LL | let _foo = Vec::new(); LL | let _foo = Vec::new();
| ---- ^^^^^^^^ cannot infer type for `T` | ---- ^^^^^^^^ 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 error: aborting due to previous error


Expand Down

0 comments on commit 8bb094d

Please sign in to comment.