Skip to content
Permalink
Browse files

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.
  • Loading branch information...
estebank committed May 30, 2019
1 parent 7840a0b commit 8bb094dac596a98cd3347979984834fe67bf3fcb
@@ -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,13 +116,18 @@ 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 {
let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
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);
@@ -4,5 +4,5 @@ fn new<T>() -> &'static T {

fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~^ ERROR type annotations needed
}
@@ -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();
@@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T {

fn main() {
let &v = new();
//~^ ERROR type annotations needed [E0282]
//~^ ERROR type annotations needed
}
@@ -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();
@@ -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

@@ -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() {
@@ -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

@@ -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();
@@ -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

@@ -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();
}

@@ -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
@@ -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`
|
@@ -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

@@ -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)

@@ -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![], );
@@ -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
@@ -1,4 +1,4 @@
fn main() {
let _foo = Vec::new();
//~^ ERROR type annotations needed [E0282]
//~^ ERROR type annotations needed
}
@@ -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

0 comments on commit 8bb094d

Please sign in to comment.
You can’t perform that action at this time.