@@ -15,17 +15,18 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
15
15
hir_map : & ' a hir:: map:: Map < ' gcx > ,
16
16
found_local_pattern : Option < & ' gcx Pat > ,
17
17
found_arg_pattern : Option < & ' gcx Pat > ,
18
+ found_ty : Option < Ty < ' tcx > > ,
18
19
}
19
20
20
21
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 > > {
22
23
let ty_opt = self . infcx . in_progress_tables . and_then ( |tables| {
23
24
tables. borrow ( ) . node_type_opt ( hir_id)
24
25
} ) ;
25
26
match ty_opt {
26
27
Some ( ty) => {
27
28
let ty = self . infcx . resolve_vars_if_possible ( & ty) ;
28
- ty. walk ( ) . any ( |inner_ty| {
29
+ if ty. walk ( ) . any ( |inner_ty| {
29
30
inner_ty == self . target_ty || match ( & inner_ty. sty , & self . target_ty . sty ) {
30
31
( & Infer ( TyVar ( a_vid) ) , & Infer ( TyVar ( b_vid) ) ) => {
31
32
self . infcx
@@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
35
36
}
36
37
_ => false ,
37
38
}
38
- } )
39
+ } ) {
40
+ Some ( ty)
41
+ } else {
42
+ None
43
+ }
39
44
}
40
- None => false ,
45
+ None => None ,
41
46
}
42
47
}
43
48
}
@@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
48
53
}
49
54
50
55
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 ) ) {
52
57
self . found_local_pattern = Some ( & * local. pat ) ;
58
+ self . found_ty = Some ( ty) ;
53
59
}
54
60
intravisit:: walk_local ( self , local) ;
55
61
}
56
62
57
63
fn visit_body ( & mut self , body : & ' gcx Body ) {
58
64
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
+ ) {
60
69
self . found_arg_pattern = Some ( & * argument. pat ) ;
70
+ self . found_ty = Some ( ty) ;
61
71
}
62
72
}
63
73
intravisit:: walk_body ( self , body) ;
@@ -98,21 +108,68 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
98
108
let name = self . extract_type_name ( & ty, None ) ;
99
109
100
110
let mut err_span = span;
101
- let mut labels = vec ! [ ( span, InferCtxt :: missing_type_msg( & name) ) ] ;
102
111
103
112
let mut local_visitor = FindLocalByTypeVisitor {
104
113
infcx : & self ,
105
114
target_ty : ty,
106
115
hir_map : & self . tcx . hir ( ) ,
107
116
found_local_pattern : None ,
108
117
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
109
134
} ;
110
135
111
136
if let Some ( body_id) = body_id {
112
137
let expr = self . tcx . hir ( ) . expect_expr_by_hir_id ( body_id. hir_id ) ;
113
138
local_visitor. visit_expr ( expr) ;
114
139
}
115
140
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
+
116
173
if let Some ( pattern) = local_visitor. found_arg_pattern {
117
174
err_span = pattern. span ;
118
175
// We don't want to show the default label for closures.
@@ -128,31 +185,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
128
185
// After clearing, it looks something like this:
129
186
// ```
130
187
// 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
132
190
// ```
133
191
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
+ ) ) ;
136
196
} else if let Some ( pattern) = local_visitor. found_local_pattern {
137
197
if let Some ( simple_ident) = pattern. simple_ident ( ) {
138
198
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
+ ) ) ,
141
203
Some ( CompilerDesugaringKind :: ForLoop ) => labels. push ( (
142
204
pattern. span ,
143
205
"the element type for this iterator is not specified" . to_owned ( ) ,
144
206
) ) ,
145
207
_ => { }
146
208
}
147
209
} 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 ) ) ) ;
149
211
}
150
- }
212
+ } ;
151
213
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
+ ) ;
156
221
157
222
for ( target_span, label_message) in labels {
158
223
err. span_label ( target_span, label_message) ;
0 commit comments