@@ -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) ;
@@ -106,13 +116,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
106
116
hir_map : & self . tcx . hir ( ) ,
107
117
found_local_pattern : None ,
108
118
found_arg_pattern : None ,
119
+ found_ty : None ,
109
120
} ;
110
121
111
122
if let Some ( body_id) = body_id {
112
123
let expr = self . tcx . hir ( ) . expect_expr_by_hir_id ( body_id. hir_id ) ;
113
124
local_visitor. visit_expr ( expr) ;
114
125
}
115
126
127
+ let ty_msg = match local_visitor. found_ty {
128
+ Some ( ty) if & ty. to_string ( ) != "_" => format ! ( " for `{}`" , ty) ,
129
+ _ => String :: new ( ) ,
130
+ } ;
116
131
if let Some ( pattern) = local_visitor. found_arg_pattern {
117
132
err_span = pattern. span ;
118
133
// We don't want to show the default label for closures.
@@ -131,13 +146,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
131
146
// ^ consider giving this closure parameter a type
132
147
// ```
133
148
labels. clear ( ) ;
134
- labels. push (
135
- ( pattern. span , "consider giving this closure parameter a type" . to_owned ( ) ) ) ;
149
+ labels. push ( ( pattern. span , format ! (
150
+ "consider giving this closure parameter {}" ,
151
+ match local_visitor. found_ty {
152
+ Some ( ty) if & ty. to_string( ) != "_" => format!(
153
+ "the type `{}` with the type parameter `{}` specified" ,
154
+ ty,
155
+ name,
156
+ ) ,
157
+ _ => "a type" . to_owned( ) ,
158
+ } ,
159
+ ) ) ) ;
136
160
} else if let Some ( pattern) = local_visitor. found_local_pattern {
137
161
if let Some ( simple_ident) = pattern. simple_ident ( ) {
138
162
match pattern. span . compiler_desugaring_kind ( ) {
139
- None => labels. push ( ( pattern. span ,
140
- format ! ( "consider giving `{}` a type" , simple_ident) ) ) ,
163
+ None => labels. push ( (
164
+ pattern. span ,
165
+ format ! (
166
+ "consider giving `{}` {}" ,
167
+ simple_ident,
168
+ match local_visitor. found_ty {
169
+ Some ( ty) if & ty. to_string( ) != "_" => format!(
170
+ "the type `{}` with the type parameter `{}` specified" ,
171
+ ty,
172
+ name,
173
+ ) ,
174
+ _ => "a type" . to_owned( ) ,
175
+ } ,
176
+ ) ,
177
+ ) ) ,
141
178
Some ( CompilerDesugaringKind :: ForLoop ) => labels. push ( (
142
179
pattern. span ,
143
180
"the element type for this iterator is not specified" . to_owned ( ) ,
@@ -147,12 +184,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
147
184
} else {
148
185
labels. push ( ( pattern. span , "consider giving the pattern a type" . to_owned ( ) ) ) ;
149
186
}
150
- }
187
+ } ;
151
188
152
- let mut err = struct_span_err ! ( self . tcx. sess,
153
- err_span,
154
- E0282 ,
155
- "type annotations needed" ) ;
189
+ let mut err = struct_span_err ! (
190
+ self . tcx. sess,
191
+ err_span,
192
+ E0282 ,
193
+ "type annotations needed{}" ,
194
+ ty_msg,
195
+ ) ;
156
196
157
197
for ( target_span, label_message) in labels {
158
198
err. span_label ( target_span, label_message) ;
0 commit comments