@@ -24,8 +24,8 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
2424 infcx : & ' a InferCtxt < ' a , ' tcx > ,
2525 target_ty : Ty < ' tcx > ,
2626 hir_map : & ' a hir:: map:: Map < ' tcx > ,
27- ) -> FindLocalByTypeVisitor < ' a , ' tcx > {
28- FindLocalByTypeVisitor {
27+ ) -> Self {
28+ Self {
2929 infcx,
3030 target_ty,
3131 hir_map,
@@ -101,6 +101,50 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
101101 }
102102}
103103
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+
104148impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
105149 pub fn extract_type_name (
106150 & self ,
@@ -160,24 +204,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
160204 span
161205 } ;
162206
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+
163213 let ty_msg = match local_visitor. found_ty {
164214 Some ( ty:: TyS { sty : ty:: Closure ( def_id, substs) , .. } ) => {
165215 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) ;
174217 let ret = fn_sig. output ( ) . skip_binder ( ) . to_string ( ) ;
175218 format ! ( " for the closure `fn({}) -> {}`" , args, ret)
176219 }
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) => {
181221 let ty = ty_to_string ( ty) ;
182222 format ! ( " for `{}`" , ty)
183223 }
@@ -211,59 +251,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
211251 let ret = fn_sig. output ( ) . skip_binder ( ) . to_string ( ) ;
212252
213253 if let Some ( ExprKind :: Closure ( _, decl, body_id, ..) ) = local_visitor. found_closure {
214- let ( arrow, post) = match decl. output {
215- FunctionRetTy :: DefaultReturn ( _) => ( "-> " , " " ) ,
216- _ => ( "" , "" ) ,
217- } ;
218254 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,
234262 ) ;
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.
236265 return err;
237266 }
238267 }
239268
240269 // 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) ;
249271 // This suggestion is incomplete, as the user will get further type inference
250272 // errors due to the `_` placeholders and the introduction of `Box`, but it does
251273 // nudge them in the right direction.
252274 format ! ( "a boxed closure type like `Box<dyn Fn({}) -> {}>`" , args, ret)
253275 }
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 == "_" => {
259277 let ty = ty_to_string ( ty) ;
260278 format ! ( "the explicit type `{}`, with the type parameters specified" , ty)
261279 }
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 => {
267281 let ty = ty_to_string ( ty) ;
268282 format ! (
269283 "the explicit type `{}`, where the type parameter `{}` is specified" ,
@@ -296,25 +310,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
296310 format ! ( "consider giving this closure parameter {}" , suffix) ,
297311 ) ;
298312 } 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 ( ) {
300314 match pattern. span . desugaring_kind ( ) {
301315 None => {
302- err. span_label (
303- pattern. span ,
304- format ! ( "consider giving `{}` {}" , simple_ident, suffix) ,
305- ) ;
316+ format ! ( "consider giving `{}` {}" , simple_ident, suffix)
306317 }
307318 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 ( )
312320 }
313- _ => { }
321+ _ => format ! ( "this needs {}" , suffix ) ,
314322 }
315323 } 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) ;
318327 }
319328 if !err. span . span_labels ( ) . iter ( ) . any ( |span_label| {
320329 span_label. label . is_some ( ) && span_label. span == span
0 commit comments