Skip to content

Commit 74fb3bb

Browse files
committed
On type inference errors use the type argument name when possible
``` error[E0282]: type annotations needed in `std::result::Result<i32, E>` --> file7.rs:3:13 | 3 | let b = Ok(4); | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>` | | | consider giving `b` a type` ```
1 parent 65c2a7b commit 74fb3bb

12 files changed

+81
-28
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
1515
hir_map: &'a hir::map::Map<'gcx>,
1616
found_local_pattern: Option<&'gcx Pat>,
1717
found_arg_pattern: Option<&'gcx Pat>,
18-
found_ty: Option<String>,
18+
found_ty: Option<Ty<'tcx>>,
1919
}
2020

2121
impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
@@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
5555
fn visit_local(&mut self, local: &'gcx Local) {
5656
if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
5757
self.found_local_pattern = Some(&*local.pat);
58-
self.found_ty = Some(ty.to_string());
58+
self.found_ty = Some(ty);
5959
}
6060
intravisit::walk_local(self, local);
6161
}
@@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
6767
self.node_matches_type(argument.hir_id),
6868
) {
6969
self.found_arg_pattern = Some(&*argument.pat);
70-
self.found_ty = Some(ty.to_string());
70+
self.found_ty = Some(ty);
7171
}
7272
}
7373
intravisit::walk_body(self, body);
@@ -117,14 +117,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
117117
found_arg_pattern: None,
118118
found_ty: None,
119119
};
120+
let ty_to_string = |ty: Ty<'tcx>| -> String {
121+
let mut s = String::new();
122+
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
123+
let ty_vars = self.type_variables.borrow();
124+
let getter = move |ty_vid| {
125+
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
126+
*ty_vars.var_origin(ty_vid) {
127+
return Some(name.to_string());
128+
}
129+
None
130+
};
131+
printer.name_resolver = Some(Box::new(&getter));
132+
let _ = ty.print(printer);
133+
s
134+
};
120135

121136
if let Some(body_id) = body_id {
122137
let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
123138
local_visitor.visit_expr(expr);
124139
}
125140

141+
// When `name` corresponds to a type argument, show the path of the full type we're
142+
// trying to infer. In the following example, `ty_msg` contains
143+
// " in `std::result::Result<i32, E>`":
144+
// ```
145+
// error[E0282]: type annotations needed in `std::result::Result<i32, E>`
146+
// --> file.rs:L:CC
147+
// |
148+
// L | let b = Ok(4);
149+
// | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
150+
// | |
151+
// | consider giving `b` a type
152+
// ```
126153
let ty_msg = match &local_visitor.found_ty {
127-
Some(ty) if &ty[..] != "_" && ty != &name => format!(" in `{}`", ty),
154+
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
155+
format!(" in `{}`", ty_to_string(ty))
156+
}
128157
_ => String::new(),
129158
};
130159
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name, &ty_msg))];
@@ -144,17 +173,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
144173
// After clearing, it looks something like this:
145174
// ```
146175
// let x = |_| { };
147-
// ^ consider giving this closure parameter a type
176+
// ^ consider giving this closure parameter the type `[_; 0]`
177+
// with the type parameter `_` specified
148178
// ```
149179
labels.clear();
150180
labels.push((pattern.span, format!(
151181
"consider giving this closure parameter {}",
152182
match &local_visitor.found_ty {
153-
Some(ty) if &ty[..] != "_" && ty != &name => format!(
154-
"the type `{}` with the type parameter `{}` specified",
155-
ty,
156-
name,
157-
),
183+
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
184+
format!(
185+
"the type `{}` with the type parameter `{}` specified",
186+
ty_to_string(ty),
187+
name,
188+
)
189+
}
158190
_ => "a type".to_owned(),
159191
},
160192
)));

src/librustc/ty/print/pretty.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,17 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
483483
ty::FnPtr(ref bare_fn) => {
484484
p!(print(bare_fn))
485485
}
486-
ty::Infer(infer_ty) => p!(write("{}", infer_ty)),
486+
ty::Infer(infer_ty) => {
487+
if let ty::TyVar(ty_vid) = infer_ty {
488+
if let Some(name) = self.infer_ty_name(ty_vid) {
489+
p!(write("{}", name))
490+
} else {
491+
p!(write("{}", infer_ty))
492+
}
493+
} else {
494+
p!(write("{}", infer_ty))
495+
}
496+
},
487497
ty::Error => p!(write("[type error]")),
488498
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
489499
ty::Bound(debruijn, bound_ty) => {
@@ -681,6 +691,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
681691
Ok(self)
682692
}
683693

694+
fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
695+
None
696+
}
697+
684698
fn pretty_print_dyn_existential(
685699
mut self,
686700
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
@@ -931,6 +945,8 @@ pub struct FmtPrinterData<'a, 'gcx, 'tcx, F> {
931945
binder_depth: usize,
932946

933947
pub region_highlight_mode: RegionHighlightMode,
948+
949+
pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>,
934950
}
935951

936952
impl<F> Deref for FmtPrinter<'a, 'gcx, 'tcx, F> {
@@ -957,6 +973,7 @@ impl<F> FmtPrinter<'a, 'gcx, 'tcx, F> {
957973
region_index: 0,
958974
binder_depth: 0,
959975
region_highlight_mode: RegionHighlightMode::default(),
976+
name_resolver: None,
960977
}))
961978
}
962979
}
@@ -1206,6 +1223,10 @@ impl<F: fmt::Write> Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
12061223
}
12071224

12081225
impl<F: fmt::Write> PrettyPrinter<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
1226+
fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> {
1227+
self.0.name_resolver.as_ref().and_then(|func| func(id))
1228+
}
1229+
12091230
fn print_value_path(
12101231
mut self,
12111232
def_id: DefId,

src/test/ui/issues/issue-12187-1.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0282]: type annotations needed in `&_`
1+
error[E0282]: type annotations needed in `&T`
22
--> $DIR/issue-12187-1.rs:6:10
33
|
44
LL | let &v = new();

src/test/ui/issues/issue-12187-2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0282]: type annotations needed in `&_`
1+
error[E0282]: type annotations needed in `&T`
22
--> $DIR/issue-12187-2.rs:6:10
33
|
44
LL | let &v = new();

src/test/ui/issues/issue-17551.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `B<_>`
1+
error[E0282]: type annotations needed in `B<T>`
22
--> $DIR/issue-17551.rs:6:15
33
|
44
LL | let foo = B(marker::PhantomData);
5-
| --- ^ cannot infer type for `T` in `B<_>`
5+
| --- ^ cannot infer type for `T` in `B<T>`
66
| |
77
| consider giving `foo` a type
88

src/test/ui/issues/issue-23046.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `Expr<'_, _>`
1+
error[E0282]: type annotations needed in `Expr<'_, VAR>`
22
--> $DIR/issue-23046.rs:17:15
33
|
44
LL | let ex = |x| {
5-
| ^ consider giving this closure parameter the type `Expr<'_, _>` with the type parameter `VAR` specified
5+
| ^ consider giving this closure parameter the type `Expr<'_, VAR>` with the type parameter `VAR` specified
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-25368.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0282]: type annotations needed in `(std::sync::mpsc::Sender<Foo<_>>, std::sync::mpsc::Receiver<Foo<_>>)`
1+
error[E0282]: type annotations needed in `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
22
--> $DIR/issue-25368.rs:11:17
33
|
44
LL | let (tx, rx) = channel();
55
| -------- consider giving the pattern a type
66
...
77
LL | tx.send(Foo{ foo: PhantomData });
8-
| ^^^ cannot infer type for `T` in `(std::sync::mpsc::Sender<Foo<_>>, std::sync::mpsc::Receiver<Foo<_>>)`
8+
| ^^^ cannot infer type for `T` in `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
99

1010
error: aborting due to previous error
1111

src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `std::vec::Vec<_>`
1+
error[E0282]: type annotations needed in `std::vec::Vec<T>`
22
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
33
|
44
LL | let mut x = Vec::new();
5-
| ----- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<_>`
5+
| ----- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>`
66
| |
77
| consider giving `x` a type
88

src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `std::vec::Vec<_>`
1+
error[E0282]: type annotations needed in `std::vec::Vec<T>`
22
--> $DIR/cannot_infer_local_or_vec.rs:2:13
33
|
44
LL | let x = vec![];
5-
| - ^^^^^^ cannot infer type for `T` in `std::vec::Vec<_>`
5+
| - ^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>`
66
| |
77
| consider giving `x` a type
88
|

src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `(std::vec::Vec<_>,)`
1+
error[E0282]: type annotations needed in `(std::vec::Vec<T>,)`
22
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
33
|
44
LL | let (x, ) = (vec![], );
5-
| ----- ^^^^^^ cannot infer type for `T` in `(std::vec::Vec<_>,)`
5+
| ----- ^^^^^^ cannot infer type for `T` in `(std::vec::Vec<T>,)`
66
| |
77
| consider giving the pattern a type
88
|

src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0282]: type annotations needed in `std::option::Option<_>`
1+
error[E0282]: type annotations needed in `std::option::Option<T>`
22
--> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
33
|
44
LL | let mut closure0 = None;

src/test/ui/vector-no-ann.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed in `std::vec::Vec<_>`
1+
error[E0282]: type annotations needed in `std::vec::Vec<T>`
22
--> $DIR/vector-no-ann.rs:2:16
33
|
44
LL | let _foo = Vec::new();
5-
| ---- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<_>`
5+
| ---- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>`
66
| |
77
| consider giving `_foo` a type
88

0 commit comments

Comments
 (0)