@@ -24,8 +24,8 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
24
24
infcx : & ' a InferCtxt < ' a , ' tcx > ,
25
25
target_ty : Ty < ' tcx > ,
26
26
hir_map : & ' a hir:: map:: Map < ' tcx > ,
27
- ) -> FindLocalByTypeVisitor < ' a , ' tcx > {
28
- FindLocalByTypeVisitor {
27
+ ) -> Self {
28
+ Self {
29
29
infcx,
30
30
target_ty,
31
31
hir_map,
@@ -101,6 +101,50 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
101
101
}
102
102
}
103
103
104
+ /// Suggest giving an appropriate return type to a closure expression.
105
+ fn closure_return_type_suggestion (
106
+ span : Span ,
107
+ err : & mut DiagnosticBuilder < ' _ > ,
108
+ output : & FunctionRetTy ,
109
+ body : & Body ,
110
+ name : & str ,
111
+ ret : & str ,
112
+ ) {
113
+ let ( arrow, post) = match output {
114
+ FunctionRetTy :: DefaultReturn ( _) => ( "-> " , " " ) ,
115
+ _ => ( "" , "" ) ,
116
+ } ;
117
+ let suggestion = match body. value . node {
118
+ ExprKind :: Block ( ..) => {
119
+ vec ! [ ( output. span( ) , format!( "{}{}{}" , arrow, ret, post) ) ]
120
+ }
121
+ _ => {
122
+ vec ! [
123
+ ( output. span( ) , format!( "{}{}{}{{ " , arrow, ret, post) ) ,
124
+ ( body. value. span. shrink_to_hi( ) , " }" . to_string( ) ) ,
125
+ ]
126
+ }
127
+ } ;
128
+ err. multipart_suggestion (
129
+ "give this closure an explicit return type without `_` placeholders" ,
130
+ suggestion,
131
+ Applicability :: HasPlaceholders ,
132
+ ) ;
133
+ err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
134
+ }
135
+
136
+ /// Given a closure signature, return a `String` containing a list of all its argument types.
137
+ fn closure_args ( fn_sig : & ty:: PolyFnSig < ' _ > ) -> String {
138
+ fn_sig. inputs ( )
139
+ . skip_binder ( )
140
+ . iter ( )
141
+ . next ( )
142
+ . map ( |args| args. tuple_fields ( )
143
+ . map ( |arg| arg. to_string ( ) )
144
+ . collect :: < Vec < _ > > ( ) . join ( ", " ) )
145
+ . unwrap_or_default ( )
146
+ }
147
+
104
148
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
105
149
pub fn extract_type_name (
106
150
& self ,
@@ -160,24 +204,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
160
204
span
161
205
} ;
162
206
207
+ let is_named_and_not_impl_trait = |ty : Ty < ' _ > | {
208
+ & ty. to_string ( ) != "_" &&
209
+ // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
210
+ ( !ty. is_impl_trait ( ) || self . tcx . features ( ) . impl_trait_in_bindings )
211
+ } ;
212
+
163
213
let ty_msg = match local_visitor. found_ty {
164
214
Some ( ty:: TyS { sty : ty:: Closure ( def_id, substs) , .. } ) => {
165
215
let fn_sig = substs. closure_sig ( * def_id, self . tcx ) ;
166
- let args = fn_sig. inputs ( )
167
- . skip_binder ( )
168
- . iter ( )
169
- . next ( )
170
- . map ( |args| args. tuple_fields ( )
171
- . map ( |arg| arg. to_string ( ) )
172
- . collect :: < Vec < _ > > ( ) . join ( ", " ) )
173
- . unwrap_or_default ( ) ;
216
+ let args = closure_args ( & fn_sig) ;
174
217
let ret = fn_sig. output ( ) . skip_binder ( ) . to_string ( ) ;
175
218
format ! ( " for the closure `fn({}) -> {}`" , args, ret)
176
219
}
177
- Some ( ty) if & ty. to_string ( ) != "_" &&
178
- // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
179
- ( !ty. is_impl_trait ( ) || self . tcx . features ( ) . impl_trait_in_bindings ) =>
180
- {
220
+ Some ( ty) if is_named_and_not_impl_trait ( ty) => {
181
221
let ty = ty_to_string ( ty) ;
182
222
format ! ( " for `{}`" , ty)
183
223
}
@@ -211,59 +251,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
211
251
let ret = fn_sig. output ( ) . skip_binder ( ) . to_string ( ) ;
212
252
213
253
if let Some ( ExprKind :: Closure ( _, decl, body_id, ..) ) = local_visitor. found_closure {
214
- let ( arrow, post) = match decl. output {
215
- FunctionRetTy :: DefaultReturn ( _) => ( "-> " , " " ) ,
216
- _ => ( "" , "" ) ,
217
- } ;
218
254
if let Some ( body) = self . tcx . hir ( ) . krate ( ) . bodies . get ( body_id) {
219
- let suggestion = match body. value . node {
220
- ExprKind :: Block ( ..) => {
221
- vec ! [ ( decl. output. span( ) , format!( "{}{}{}" , arrow, ret, post) ) ]
222
- }
223
- _ => {
224
- vec ! [
225
- ( decl. output. span( ) , format!( "{}{}{}{{ " , arrow, ret, post) ) ,
226
- ( body. value. span. shrink_to_hi( ) , " }" . to_string( ) ) ,
227
- ]
228
- }
229
- } ;
230
- err. multipart_suggestion (
231
- "give this closure an explicit return type without `_` placeholders" ,
232
- suggestion,
233
- Applicability :: HasPlaceholders ,
255
+ closure_return_type_suggestion (
256
+ span,
257
+ & mut err,
258
+ & decl. output ,
259
+ & body,
260
+ & name,
261
+ & ret,
234
262
) ;
235
- err. span_label ( span, InferCtxt :: missing_type_msg ( & name) ) ;
263
+ // We don't want to give the other suggestions when the problem is the
264
+ // closure return type.
236
265
return err;
237
266
}
238
267
}
239
268
240
269
// This shouldn't be reachable, but just in case we leave a reasonable fallback.
241
- let args = fn_sig. inputs ( )
242
- . skip_binder ( )
243
- . iter ( )
244
- . next ( )
245
- . map ( |args| args. tuple_fields ( )
246
- . map ( |arg| arg. to_string ( ) )
247
- . collect :: < Vec < _ > > ( ) . join ( ", " ) )
248
- . unwrap_or_default ( ) ;
270
+ let args = closure_args ( & fn_sig) ;
249
271
// This suggestion is incomplete, as the user will get further type inference
250
272
// errors due to the `_` placeholders and the introduction of `Box`, but it does
251
273
// nudge them in the right direction.
252
274
format ! ( "a boxed closure type like `Box<dyn Fn({}) -> {}>`" , args, ret)
253
275
}
254
- Some ( ty) if & ty. to_string ( ) != "_" &&
255
- name == "_" &&
256
- // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
257
- ( !ty. is_impl_trait ( ) || self . tcx . features ( ) . impl_trait_in_bindings ) =>
258
- {
276
+ Some ( ty) if is_named_and_not_impl_trait ( ty) && name == "_" => {
259
277
let ty = ty_to_string ( ty) ;
260
278
format ! ( "the explicit type `{}`, with the type parameters specified" , ty)
261
279
}
262
- Some ( ty) if & ty. to_string ( ) != "_" &&
263
- ty. to_string ( ) != name &&
264
- // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
265
- ( !ty. is_impl_trait ( ) || self . tcx . features ( ) . impl_trait_in_bindings ) =>
266
- {
280
+ Some ( ty) if is_named_and_not_impl_trait ( ty) && ty. to_string ( ) != name => {
267
281
let ty = ty_to_string ( ty) ;
268
282
format ! (
269
283
"the explicit type `{}`, where the type parameter `{}` is specified" ,
@@ -296,25 +310,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
296
310
format ! ( "consider giving this closure parameter {}" , suffix) ,
297
311
) ;
298
312
} else if let Some ( pattern) = local_visitor. found_local_pattern {
299
- if let Some ( simple_ident) = pattern. simple_ident ( ) {
313
+ let msg = if let Some ( simple_ident) = pattern. simple_ident ( ) {
300
314
match pattern. span . desugaring_kind ( ) {
301
315
None => {
302
- err. span_label (
303
- pattern. span ,
304
- format ! ( "consider giving `{}` {}" , simple_ident, suffix) ,
305
- ) ;
316
+ format ! ( "consider giving `{}` {}" , simple_ident, suffix)
306
317
}
307
318
Some ( DesugaringKind :: ForLoop ) => {
308
- err. span_label (
309
- pattern. span ,
310
- "the element type for this iterator is not specified" . to_string ( ) ,
311
- ) ;
319
+ "the element type for this iterator is not specified" . to_string ( )
312
320
}
313
- _ => { }
321
+ _ => format ! ( "this needs {}" , suffix ) ,
314
322
}
315
323
} else {
316
- err. span_label ( pattern. span , format ! ( "consider giving this pattern {}" , suffix) ) ;
317
- }
324
+ format ! ( "consider giving this pattern {}" , suffix)
325
+ } ;
326
+ err. span_label ( pattern. span , msg) ;
318
327
}
319
328
if !err. span . span_labels ( ) . iter ( ) . any ( |span_label| {
320
329
span_label. label . is_some ( ) && span_label. span == span
0 commit comments