diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index aae7b5e1202d4..85ff1cbc9e4d6 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -15,7 +15,7 @@ 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, + found_ty: Option>, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn visit_local(&mut self, local: &'gcx Local) { 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.to_string()); + self.found_ty = Some(ty); } intravisit::walk_local(self, local); } @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { self.node_matches_type(argument.hir_id), ) { self.found_arg_pattern = Some(&*argument.pat); - self.found_ty = Some(ty.to_string()); + self.found_ty = Some(ty); } } intravisit::walk_body(self, body); @@ -117,14 +117,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 { let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id); 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 in `std::result::Result` + // --> file.rs:L:CC + // | + // L | let b = Ok(4); + // | - ^^ cannot infer type for `E` in `std::result::Result` + // | | + // | consider giving `b` a type + // ``` let ty_msg = match &local_visitor.found_ty { - Some(ty) if &ty[..] != "_" && ty != &name => format!(" in `{}`", ty), + Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => { + format!(" in `{}`", ty_to_string(ty)) + } _ => String::new(), }; let mut labels = vec![(span, InferCtxt::missing_type_msg(&name, &ty_msg))]; @@ -144,17 +173,20 @@ 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, format!( "consider giving this closure parameter {}", match &local_visitor.found_ty { - Some(ty) if &ty[..] != "_" && ty != &name => format!( - "the type `{}` with the type parameter `{}` specified", - ty, - name, - ), + Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => { + format!( + "the type `{}` with the type parameter `{}` specified", + ty_to_string(ty), + name, + ) + } _ => "a type".to_owned(), }, ))); diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index a246d9652f2f0..cd617a9368d85 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.stderr b/src/test/ui/issues/issue-12187-1.stderr index 510eeb4b9bbd7..5f07dbc6673d9 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 in `&_` +error[E0282]: type annotations needed in `&T` --> $DIR/issue-12187-1.rs:6:10 | LL | let &v = new(); diff --git a/src/test/ui/issues/issue-12187-2.stderr b/src/test/ui/issues/issue-12187-2.stderr index 8b12ff5f9d8c5..5b44278359cdf 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 in `&_` +error[E0282]: type annotations needed in `&T` --> $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 0d7a31fc60de6..95af1e41b58ef 100644 --- a/src/test/ui/issues/issue-17551.stderr +++ b/src/test/ui/issues/issue-17551.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed in `B<_>` +error[E0282]: type annotations needed in `B` --> $DIR/issue-17551.rs:6:15 | LL | let foo = B(marker::PhantomData); - | --- ^ cannot infer type for `T` in `B<_>` + | --- ^ cannot infer type for `T` in `B` | | | consider giving `foo` a type diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr index 1363a6f963fe0..102cfe0085fc0 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 in `Expr<'_, _>` +error[E0282]: type annotations needed in `Expr<'_, VAR>` --> $DIR/issue-23046.rs:17:15 | LL | let ex = |x| { - | ^ consider giving this closure parameter the type `Expr<'_, _>` with the type parameter `VAR` specified + | ^ consider giving this closure parameter the type `Expr<'_, VAR>` 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 5fc9ab2696970..a386fc946284f 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,11 +1,11 @@ -error[E0282]: type annotations needed in `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` +error[E0282]: type annotations needed in `(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 ... LL | tx.send(Foo{ foo: PhantomData }); - | ^^^ cannot infer type for `T` in `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` + | ^^^ cannot infer type for `T` in `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` error: aborting due to previous error 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 e8871efc5b271..b9fa36041b19e 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,8 +1,8 @@ -error[E0282]: type annotations needed in `std::vec::Vec<_>` +error[E0282]: type annotations needed in `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` in `std::vec::Vec<_>` + | ----- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec` | | | consider giving `x` a type 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 59a8b52a66d32..a491d4516cc78 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,8 +1,8 @@ -error[E0282]: type annotations needed in `std::vec::Vec<_>` +error[E0282]: type annotations needed in `std::vec::Vec` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; - | - ^^^^^^ cannot infer type for `T` in `std::vec::Vec<_>` + | - ^^^^^^ cannot infer type for `T` in `std::vec::Vec` | | | consider giving `x` a type | 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 294b6d93211b1..1c5b750b9b4a9 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,8 +1,8 @@ -error[E0282]: type annotations needed in `(std::vec::Vec<_>,)` +error[E0282]: type annotations needed in `(std::vec::Vec,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); - | ----- ^^^^^^ cannot infer type for `T` in `(std::vec::Vec<_>,)` + | ----- ^^^^^^ cannot infer type for `T` in `(std::vec::Vec,)` | | | consider giving the pattern a type | 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 142975144d47d..dda453870dcef 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,4 +1,4 @@ -error[E0282]: type annotations needed in `std::option::Option<_>` +error[E0282]: type annotations needed in `std::option::Option` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32 | LL | let mut closure0 = None; diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 2431927f2ac8c..a6c805c0c2679 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed in `std::vec::Vec<_>` +error[E0282]: type annotations needed in `std::vec::Vec` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); - | ---- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<_>` + | ---- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec` | | | consider giving `_foo` a type