diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 972ffbe1820..b3ff25a695f 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>, } 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> { 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); @@ -98,7 +108,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let name = self.extract_type_name(&ty, None); let mut err_span = span; - let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, @@ -106,6 +115,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir(), found_local_pattern: None, found_arg_pattern: None, + found_ty: None, + }; + let ty_to_string = |ty: Ty<'tcx>| -> String { + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + let ty_vars = self.type_variables.borrow(); + let getter = move |ty_vid| { + if let TypeVariableOrigin::TypeParameterDefinition(_, name) = + *ty_vars.var_origin(ty_vid) { + return Some(name.to_string()); + } + None + }; + printer.name_resolver = Some(Box::new(&getter)); + let _ = ty.print(printer); + s }; if let Some(body_id) = body_id { @@ -113,6 +138,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { local_visitor.visit_expr(expr); } + // When `name` corresponds to a type argument, show the path of the full type we're + // trying to infer. In the following example, `ty_msg` contains + // " in `std::result::Result`": + // ``` + // error[E0282]: type annotations needed for `std::result::Result` + // --> file.rs:L:CC + // | + // L | let b = Ok(4); + // | - ^^ cannot infer type for `E` in `std::result::Result` + // | | + // | consider giving `b` the explicit type `std::result::Result`, where + // | the type parameter `E` is specified + // ``` + let (ty_msg, suffix) = match &local_visitor.found_ty { + Some(ty) if &ty.to_string() != "_" && name == "_" => { + let ty = ty_to_string(ty); + (format!(" for `{}`", ty), + format!("the explicit type `{}`, with the type parameters specified", ty)) + } + Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => { + let ty = ty_to_string(ty); + (format!(" for `{}`", ty), + format!( + "the explicit type `{}`, where the type parameter `{}` is specified", + ty, + name, + )) + } + _ => (String::new(), "a type".to_owned()), + }; + let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))]; + if let Some(pattern) = local_visitor.found_arg_pattern { err_span = pattern.span; // We don't want to show the default label for closures. @@ -128,16 +185,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // After clearing, it looks something like this: // ``` // let x = |_| { }; - // ^ consider giving this closure parameter a type + // ^ consider giving this closure parameter the type `[_; 0]` + // with the type parameter `_` specified // ``` 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 {}", suffix), + )); } 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, suffix), + )), Some(CompilerDesugaringKind::ForLoop) => labels.push(( pattern.span, "the element type for this iterator is not specified".to_owned(), @@ -145,14 +207,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => {} } } else { - labels.push((pattern.span, "consider giving the pattern a type".to_owned())); + labels.push((pattern.span, format!("consider giving this pattern {}", suffix))); } - } + }; - 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/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index a8a6bca4fd4..513ffd69cca 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -483,7 +483,17 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: ty::FnPtr(ref bare_fn) => { p!(print(bare_fn)) } - ty::Infer(infer_ty) => p!(write("{}", infer_ty)), + ty::Infer(infer_ty) => { + if let ty::TyVar(ty_vid) = infer_ty { + if let Some(name) = self.infer_ty_name(ty_vid) { + p!(write("{}", name)) + } else { + p!(write("{}", infer_ty)) + } + } else { + p!(write("{}", infer_ty)) + } + }, ty::Error => p!(write("[type error]")), ty::Param(ref param_ty) => p!(write("{}", param_ty)), ty::Bound(debruijn, bound_ty) => { @@ -681,6 +691,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: Ok(self) } + fn infer_ty_name(&self, _: ty::TyVid) -> Option { + None + } + fn pretty_print_dyn_existential( mut self, predicates: &'tcx ty::List>, @@ -931,6 +945,8 @@ pub struct FmtPrinterData<'a, 'gcx, 'tcx, F> { binder_depth: usize, pub region_highlight_mode: RegionHighlightMode, + + pub name_resolver: Option Option>>, } impl Deref for FmtPrinter<'a, 'gcx, 'tcx, F> { @@ -957,6 +973,7 @@ impl FmtPrinter<'a, 'gcx, 'tcx, F> { region_index: 0, binder_depth: 0, region_highlight_mode: RegionHighlightMode::default(), + name_resolver: None, })) } } @@ -1206,6 +1223,10 @@ impl Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> { } impl PrettyPrinter<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> { + fn infer_ty_name(&self, id: ty::TyVid) -> Option { + self.0.name_resolver.as_ref().and_then(|func| func(id)) + } + fn print_value_path( mut self, def_id: DefId, 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() -> &'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..3ea15439df2 100644 --- a/src/test/ui/issues/issue-12187-1.stderr +++ b/src/test/ui/issues/issue-12187-1.stderr @@ -1,11 +1,11 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&T` --> $DIR/issue-12187-1.rs:6:10 | LL | let &v = new(); | -^ | || | |cannot infer type - | consider giving the pattern a type + | consider giving this pattern the explicit type `&T`, with the type parameters specified error: aborting due to previous error 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..a5e65c65beb 100644 --- a/src/test/ui/issues/issue-12187-2.stderr +++ b/src/test/ui/issues/issue-12187-2.stderr @@ -1,11 +1,11 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `&T` --> $DIR/issue-12187-2.rs:6:10 | LL | let &v = new(); | -^ | || | |cannot infer type - | consider giving the pattern a type + | consider giving this pattern the explicit type `&T`, with the type parameters specified error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr index 40e7727752b..ce16f0f58ea 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 explicit type `B`, where the type parameter `T` is 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..12b2eb48e7e 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<'_, VAR>` --> $DIR/issue-23046.rs:17:15 | LL | let ex = |x| { - | ^ consider giving this closure parameter a type + | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is 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..0b890b573da 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` --> $DIR/issue-25368.rs:11:17 | LL | let (tx, rx) = channel(); - | -------- consider giving the pattern a type + | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... LL | tx.send(Foo{ foo: PhantomData }); | ^^^ cannot infer type for `T` diff --git a/src/test/ui/issues/issue-7813.stderr b/src/test/ui/issues/issue-7813.stderr index 45b9c915885..59be0f3be11 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 explicit type `&[_; 0]`, with the type parameters 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 { 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..b1bd749bef4 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 explicit type `std::vec::Vec`, where the type parameter `T` is 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..04c2870d832 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 explicit type `std::option::Option<_>`, where the type parameter `T` is 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..8edec6e0ea3 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 explicit type `[_; 0]`, with the type parameters 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..6524bf5dd2b 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 explicit type `std::vec::Vec`, where the type parameter `T` is 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..6d1ef240da6 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,10 +1,10 @@ -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![], ); | ----- ^^^^^^ cannot infer type for `T` | | - | consider giving the pattern a type + | consider giving this pattern the explicit type `(std::vec::Vec,)`, where the type parameter `T` is 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/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index bd58e241f0c..18af3dc640d 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 explicit type `std::option::Option`, with the type parameters 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..28100d7c89e 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 explicit type `std::vec::Vec`, where the type parameter `T` is specified error: aborting due to previous error