Skip to content

Commit d59dcb2

Browse files
committed
Auto merge of #61361 - estebank:infer-type, r=varkor
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 in `std::vec::Vec<T>` --> $DIR/vector-no-ann.rs:2:16 | LL | let foo = Vec::new(); | --- ^^^^^^^^ cannot infer type for `T` in `std::vec::Vec<T>` | | | consider giving `foo` a type ``` Fix #25633.
2 parents 3a6bef0 + e420f44 commit d59dcb2

20 files changed

+136
-50
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

+83-18
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ 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<Ty<'tcx>>,
1819
}
1920

2021
impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
21-
fn node_matches_type(&mut self, hir_id: HirId) -> bool {
22+
fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
2223
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
2324
tables.borrow().node_type_opt(hir_id)
2425
});
2526
match ty_opt {
2627
Some(ty) => {
2728
let ty = self.infcx.resolve_vars_if_possible(&ty);
28-
ty.walk().any(|inner_ty| {
29+
if ty.walk().any(|inner_ty| {
2930
inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
3031
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
3132
self.infcx
@@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
3536
}
3637
_ => false,
3738
}
38-
})
39+
}) {
40+
Some(ty)
41+
} else {
42+
None
43+
}
3944
}
40-
None => false,
45+
None => None,
4146
}
4247
}
4348
}
@@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
4853
}
4954

5055
fn visit_local(&mut self, local: &'gcx Local) {
51-
if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) {
56+
if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
5257
self.found_local_pattern = Some(&*local.pat);
58+
self.found_ty = Some(ty);
5359
}
5460
intravisit::walk_local(self, local);
5561
}
5662

5763
fn visit_body(&mut self, body: &'gcx Body) {
5864
for argument in &body.arguments {
59-
if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) {
65+
if let (None, Some(ty)) = (
66+
self.found_arg_pattern,
67+
self.node_matches_type(argument.hir_id),
68+
) {
6069
self.found_arg_pattern = Some(&*argument.pat);
70+
self.found_ty = Some(ty);
6171
}
6272
}
6373
intravisit::walk_body(self, body);
@@ -98,21 +108,68 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
98108
let name = self.extract_type_name(&ty, None);
99109

100110
let mut err_span = span;
101-
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
102111

103112
let mut local_visitor = FindLocalByTypeVisitor {
104113
infcx: &self,
105114
target_ty: ty,
106115
hir_map: &self.tcx.hir(),
107116
found_local_pattern: None,
108117
found_arg_pattern: None,
118+
found_ty: None,
119+
};
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
109134
};
110135

111136
if let Some(body_id) = body_id {
112137
let expr = self.tcx.hir().expect_expr_by_hir_id(body_id.hir_id);
113138
local_visitor.visit_expr(expr);
114139
}
115140

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 for `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` the explicit type `std::result::Result<i32, E>`, where
152+
// | the type parameter `E` is specified
153+
// ```
154+
let (ty_msg, suffix) = match &local_visitor.found_ty {
155+
Some(ty) if &ty.to_string() != "_" && name == "_" => {
156+
let ty = ty_to_string(ty);
157+
(format!(" for `{}`", ty),
158+
format!("the explicit type `{}`, with the type parameters specified", ty))
159+
}
160+
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
161+
let ty = ty_to_string(ty);
162+
(format!(" for `{}`", ty),
163+
format!(
164+
"the explicit type `{}`, where the type parameter `{}` is specified",
165+
ty,
166+
name,
167+
))
168+
}
169+
_ => (String::new(), "a type".to_owned()),
170+
};
171+
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
172+
116173
if let Some(pattern) = local_visitor.found_arg_pattern {
117174
err_span = pattern.span;
118175
// We don't want to show the default label for closures.
@@ -128,31 +185,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
128185
// After clearing, it looks something like this:
129186
// ```
130187
// let x = |_| { };
131-
// ^ consider giving this closure parameter a type
188+
// ^ consider giving this closure parameter the type `[_; 0]`
189+
// with the type parameter `_` specified
132190
// ```
133191
labels.clear();
134-
labels.push(
135-
(pattern.span, "consider giving this closure parameter a type".to_owned()));
192+
labels.push((
193+
pattern.span,
194+
format!("consider giving this closure parameter {}", suffix),
195+
));
136196
} else if let Some(pattern) = local_visitor.found_local_pattern {
137197
if let Some(simple_ident) = pattern.simple_ident() {
138198
match pattern.span.compiler_desugaring_kind() {
139-
None => labels.push((pattern.span,
140-
format!("consider giving `{}` a type", simple_ident))),
199+
None => labels.push((
200+
pattern.span,
201+
format!("consider giving `{}` {}", simple_ident, suffix),
202+
)),
141203
Some(CompilerDesugaringKind::ForLoop) => labels.push((
142204
pattern.span,
143205
"the element type for this iterator is not specified".to_owned(),
144206
)),
145207
_ => {}
146208
}
147209
} else {
148-
labels.push((pattern.span, "consider giving the pattern a type".to_owned()));
210+
labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
149211
}
150-
}
212+
};
151213

152-
let mut err = struct_span_err!(self.tcx.sess,
153-
err_span,
154-
E0282,
155-
"type annotations needed");
214+
let mut err = struct_span_err!(
215+
self.tcx.sess,
216+
err_span,
217+
E0282,
218+
"type annotations needed{}",
219+
ty_msg,
220+
);
156221

157222
for (target_span, label_message) in labels {
158223
err.span_label(target_span, label_message);

src/librustc/ty/print/pretty.rs

+22-1
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.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ fn new<T>() -> &'static T {
44

55
fn main() {
66
let &v = new();
7-
//~^ ERROR type annotations needed [E0282]
7+
//~^ ERROR type annotations needed
88
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `&T`
22
--> $DIR/issue-12187-1.rs:6:10
33
|
44
LL | let &v = new();
55
| -^
66
| ||
77
| |cannot infer type
8-
| consider giving the pattern a type
8+
| consider giving this pattern the explicit type `&T`, with the type parameters specified
99

1010
error: aborting due to previous error
1111

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ fn new<'r, T>() -> &'r T {
44

55
fn main() {
66
let &v = new();
7-
//~^ ERROR type annotations needed [E0282]
7+
//~^ ERROR type annotations needed
88
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `&T`
22
--> $DIR/issue-12187-2.rs:6:10
33
|
44
LL | let &v = new();
55
| -^
66
| ||
77
| |cannot infer type
8-
| consider giving the pattern a type
8+
| consider giving this pattern the explicit type `&T`, with the type parameters specified
99

1010
error: aborting due to previous error
1111

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `B<T>`
22
--> $DIR/issue-17551.rs:6:15
33
|
44
LL | let foo = B(marker::PhantomData);
55
| --- ^ cannot infer type for `T`
66
| |
7-
| consider giving `foo` a type
7+
| consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
88

99
error: aborting due to previous error
1010

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `&(_,)`
22
--> $DIR/issue-20261.rs:4:11
33
|
44
LL | for (ref i,) in [].iter() {

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

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

77
error: aborting due to previous error
88

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `(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();
5-
| -------- consider giving the pattern a type
5+
| -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
66
...
77
LL | tx.send(Foo{ foo: PhantomData });
88
| ^^^ cannot infer type for `T`

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `&[_; 0]`
22
--> $DIR/issue-7813.rs:2:13
33
|
44
LL | let v = &[];
55
| - ^^^ cannot infer type
66
| |
7-
| consider giving `v` a type
7+
| consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
88

99
error: aborting due to previous error
1010

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl Foo for Vec<isize> {
2222
fn m1() {
2323
// we couldn't infer the type of the vector just based on calling foo()...
2424
let mut x = Vec::new();
25-
//~^ ERROR type annotations needed [E0282]
25+
//~^ ERROR type annotations needed
2626
x.foo();
2727
}
2828

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `std::vec::Vec<T>`
22
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
33
|
44
LL | let mut x = Vec::new();
55
| ----- ^^^^^^^^ cannot infer type for `T`
66
| |
7-
| consider giving `x` a type
7+
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
88

99
error[E0308]: mismatched types
1010
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20

src/test/ui/span/issue-42234-unknown-receiver-type.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `std::option::Option<_>`
22
--> $DIR/issue-42234-unknown-receiver-type.rs:7:5
33
|
44
LL | let x: Option<_> = None;
5-
| - consider giving `x` a type
5+
| - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified
66
LL | x.unwrap().method_that_could_exist_on_some_type();
77
| ^^^^^^^^^^ cannot infer type for `T`
88
|

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `[_; 0]`
22
--> $DIR/cannot_infer_local_or_array.rs:2:13
33
|
44
LL | let x = [];
55
| - ^^ cannot infer type
66
| |
7-
| consider giving `x` a type
7+
| consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
88

99
error: aborting due to previous error
1010

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0282]: type annotations needed
1+
error[E0282]: type annotations needed for `std::vec::Vec<T>`
22
--> $DIR/cannot_infer_local_or_vec.rs:2:13
33
|
44
LL | let x = vec![];
55
| - ^^^^^^ cannot infer type for `T`
66
| |
7-
| consider giving `x` a type
7+
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
88
|
99
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1010

0 commit comments

Comments
 (0)