Skip to content

Commit

Permalink
Rollup merge of rust-lang#39361 - cengizIO:master, r=arielb1
Browse files Browse the repository at this point in the history
Improve error message for uninferrable types rust-lang#38812

Hello,

I tried to improve the error message for uninferrable types. The error code is `E0282`.

```rust

error[E0282]: type annotations needed
 --> /home/cengizIO/issue38812.rs:2:11
  |
2 |   let x = vec![];
  |       -   ^^^^^^ cannot infer type for `T`
  |       |
  |       consider giving `x` a type
  |
  = note: this error originates in a macro outside of the current crate
```

and

```rust

error[E0282]: type annotations needed
 --> /home/cengizIO/issue38812.rs:2:15
  |
2 |   let (x,) = (vec![],);
  |       ----    ^^^^^^ cannot infer type for `T`
  |       |
  |       consider giving a type to pattern
  |
  = note: this error originates in a macro outside of the current crate
```

Rust compiler now tries to find uninferred `local`s with type `_` and adds them into the error message.

I'm probably wrong on wording that I used. Please feel free to suggest better alternatives.

Thanks @nikomatsakis for mentoring 🍺

Any comments/feedback is more than welcome!

Thank you
  • Loading branch information
frewsxcv authored Feb 7, 2017
2 parents a2800cd + 3fa28cb commit 0cf50c0
Show file tree
Hide file tree
Showing 26 changed files with 124 additions and 56 deletions.
78 changes: 65 additions & 13 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ use util::nodemap::{FxHashMap, FxHashSet};
use std::cmp;
use std::fmt;
use syntax::ast;
use hir::{intravisit, Local, Pat};
use hir::intravisit::{Visitor, NestedVisitorMap};
use syntax_pos::{DUMMY_SP, Span};
use errors::DiagnosticBuilder;

Expand All @@ -60,6 +62,30 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
}
}

struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
target_ty: &'a Ty<'tcx>,
found_pattern: Option<&'a Pat>,
}

impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
NestedVisitorMap::None
}

fn visit_local(&mut self, local: &'a Local) {
if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) {
let ty = self.infcx.resolve_type_vars_if_possible(&ty);
let is_match = ty.walk().any(|t| t == *self.target_ty);

if is_match && self.found_pattern.is_none() {
self.found_pattern = Some(&*local.pat);
}
}
intravisit::walk_local(self, local);
}
}

impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
for error in errors {
Expand Down Expand Up @@ -775,7 +801,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.lang_items.sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
self.need_type_info(obligation.cause.span, self_ty);
self.need_type_info(obligation, self_ty);
} else {
let mut err = struct_span_err!(self.tcx.sess,
obligation.cause.span, E0283,
Expand All @@ -793,7 +819,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !self.tcx.sess.has_errors() {
self.need_type_info(obligation.cause.span, ty);
self.need_type_info(obligation, ty);
}
}

Expand Down Expand Up @@ -857,27 +883,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
})
}


fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = if let ty::TyInfer(ty::TyVar(ty_vid)) = ty.sty {
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
let ty_vars = self.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
*ty_vars.var_origin(ty_vid)
{
*ty_vars.var_origin(ty_vid) {
name.to_string()
} else {
ty.to_string()
}
} else {
ty.to_string()
}
}

fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty);
let ref cause = obligation.cause;

let mut err = struct_span_err!(self.tcx.sess,
cause.span,
E0282,
"type annotations needed");

err.span_label(cause.span, &format!("cannot infer type for `{}`", name));

let expr = self.tcx.hir.expect_expr(cause.body_id);

let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
target_ty: &ty,
found_pattern: None,
};

let mut err = struct_span_err!(self.tcx.sess, span, E0282,
"unable to infer enough type information about `{}`",
name);
err.note("type annotations or generic parameter binding required");
err.span_label(span, &format!("cannot infer type for `{}`", name));
local_visitor.visit_expr(expr);

if let Some(pattern) = local_visitor.found_pattern {
let pattern_span = pattern.span;
if let Some(simple_name) = pattern.simple_name() {
err.span_label(pattern_span,
&format!("consider giving `{}` a type",
simple_name));
} else {
err.span_label(pattern_span, &format!("consider giving a type to pattern"));
}
}

err.emit();
}

Expand Down
3 changes: 1 addition & 2 deletions src/test/compile-fail/issue-12187-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ fn new<T>() -> &'static T {

fn main() {
let &v = new();
//~^ ERROR unable to infer enough type information about `_` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `_`
//~| NOTE type annotations or generic parameter binding
}
3 changes: 1 addition & 2 deletions src/test/compile-fail/issue-12187-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ fn new<'r, T>() -> &'r T {

fn main() {
let &v = new();
//~^ ERROR unable to infer enough type information about `_` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `_`
//~| NOTE type annotations or generic parameter binding
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-16966.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// error-pattern:type annotations or generic parameter binding required
// error-pattern:type annotations needed
fn main() {
panic!(
std::default::Default::default()
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-17551.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ use std::marker;
struct B<T>(marker::PhantomData<T>);

fn main() {
let foo = B(marker::PhantomData); //~ ERROR unable to infer enough type information
let foo = B(marker::PhantomData); //~ ERROR type annotations needed
let closure = || foo;
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-18159.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
// except according to those terms.

fn main() {
let x; //~ ERROR unable to infer enough type information
let x; //~ ERROR type annotations needed
}
1 change: 0 additions & 1 deletion src/test/compile-fail/issue-23041.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ fn main()
let b:Box<Any> = Box::new(bar as fn(_)->_);
b.downcast_ref::<fn(_)->_>(); //~ ERROR E0282
//~| NOTE cannot infer type for `_`
//~| NOTE type annotations or generic parameter binding required
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-23046.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>

fn main() {
let ex = |x| {
let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `VAR`
let_(add(x,x), |y| { //~ ERROR type annotations needed
let_(add(x, x), |x|x)})};
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-24013.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ fn main() {
let a = 1;
let b = 2;
unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
//~^ ERROR unable to infer enough type information about `_`
//~^ ERROR type annotations needed
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-5062.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
// except according to those terms.

fn main() { format!("{:?}", None); }
//~^ ERROR unable to infer enough type information about `T` [E0282]
//~^ ERROR type annotations needed [E0282]
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-6458-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
fn main() {
// Unconstrained type:
format!("{:?}", None);
//~^ ERROR unable to infer enough type information about `T` [E0282]
//~^ ERROR type annotations needed [E0282]
}
3 changes: 1 addition & 2 deletions src/test/compile-fail/issue-6458-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use std::mem;

fn main() {
mem::transmute(0);
//~^ ERROR unable to infer enough type information about `U` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `U`
//~| NOTE type annotations or generic parameter binding
}
3 changes: 1 addition & 2 deletions src/test/compile-fail/issue-6458.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ pub fn foo<State>(_: TypeWithState<State>) {}

pub fn bar() {
foo(TypeWithState(marker::PhantomData));
//~^ ERROR unable to infer enough type information about `State` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `State`
//~| NOTE type annotations or generic parameter binding
}

fn main() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/issue-7813.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

fn main() {
let v = &[];
let it = v.iter(); //~ ERROR unable to infer enough type information about `T` [E0282]
let it = v.iter(); //~ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `T`
//~| NOTE type annotations or generic parameter binding
//~| NOTE consider giving `it` a type
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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 unable to infer enough type information about `T` [E0282]
//~^ ERROR type annotations needed [E0282]
x.foo();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ where T : Convert<U>

fn a() {
test(22, std::default::Default::default());
//~^ ERROR unable to infer enough type information about `U` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `U`
//~| NOTE type annotations or generic parameter binding
}

fn main() {}
3 changes: 1 addition & 2 deletions src/test/compile-fail/unconstrained-none.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// Issue #5062

fn main() {
None; //~ ERROR unable to infer enough type information about `T` [E0282]
None; //~ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `T`
//~| NOTE type annotations or generic parameter binding
}
3 changes: 1 addition & 2 deletions src/test/compile-fail/unconstrained-ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ struct S<'a, T:'a> {
}

fn main() {
S { o: &None }; //~ ERROR unable to infer enough type information about `T` [E0282]
S { o: &None }; //~ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `T`
//~| NOTE type annotations or generic parameter binding
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/vector-no-ann.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

fn main() {
let _foo = Vec::new();
//~^ ERROR unable to infer enough type information about `T` [E0282]
//~^ ERROR type annotations needed [E0282]
//~| NOTE cannot infer type for `T`
//~| NOTE type annotations or generic parameter binding
//~| NOTE consider giving `_foo` a type
}
13 changes: 13 additions & 0 deletions src/test/ui/codemap_tests/issue-38812-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
let (x,) = (vec![],);
}
12 changes: 12 additions & 0 deletions src/test/ui/codemap_tests/issue-38812-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0282]: type annotations needed
--> $DIR/issue-38812-2.rs:12:17
|
12 | let (x,) = (vec![],);
| ---- ^^^^^^ cannot infer type for `T`
| |
| consider giving a type to pattern
|
= note: this error originates in a macro outside of the current crate

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/codemap_tests/issue-38812.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0282]: type annotations needed
--> $DIR/issue-38812.rs:12:13
|
12 | let x = vec![];
| - ^^^^^^ cannot infer type for `T`
| |
| consider giving `x` a type
|
= note: this error originates in a macro outside of the current crate

error: aborting due to previous error

11 changes: 0 additions & 11 deletions src/test/ui/codemap_tests/repair_span_std_macros.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion src/test/ui/missing-items/missing-type-parameter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/missing-items/missing-type-parameter.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
error[E0282]: unable to infer enough type information about `X`
error[E0282]: type annotations needed
--> $DIR/missing-type-parameter.rs:14:5
|
14 | foo();
| ^^^ cannot infer type for `X`
|
= note: type annotations or generic parameter binding required

error: aborting due to previous error

0 comments on commit 0cf50c0

Please sign in to comment.