@@ -1238,60 +1238,109 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1238
1238
points_at_arg : bool ,
1239
1239
) {
1240
1240
let self_ty = trait_ref. self_ty ( ) ;
1241
- match self_ty. kind {
1241
+ let ( def_id, output_ty, callable) = match self_ty. kind {
1242
+ ty:: Closure ( def_id, substs) => {
1243
+ ( def_id, self . closure_sig ( def_id, substs) . output ( ) , "closure" )
1244
+ }
1242
1245
ty:: FnDef ( def_id, _) => {
1243
- // We tried to apply the bound to an `fn`. Check whether calling it would evaluate
1244
- // to a type that *would* satisfy the trait binding. If it would, suggest calling
1245
- // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is
1246
- // `async`.
1247
- let output_ty = self_ty. fn_sig ( self . tcx ) . output ( ) ;
1248
- let new_trait_ref = ty:: TraitRef {
1249
- def_id : trait_ref. def_id ( ) ,
1250
- substs : self . tcx . mk_substs_trait ( output_ty. skip_binder ( ) , & [ ] ) ,
1251
- } ;
1252
- let obligation = Obligation :: new (
1253
- obligation. cause . clone ( ) ,
1254
- obligation. param_env ,
1255
- new_trait_ref. to_predicate ( ) ,
1256
- ) ;
1257
- match self . evaluate_obligation ( & obligation) {
1258
- Ok ( EvaluationResult :: EvaluatedToOk ) |
1259
- Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) |
1260
- Ok ( EvaluationResult :: EvaluatedToAmbig ) => {
1261
- if let Some ( hir:: Node :: Item ( hir:: Item {
1262
- ident,
1263
- kind : hir:: ItemKind :: Fn ( .., body_id) ,
1264
- ..
1265
- } ) ) = self . tcx . hir ( ) . get_if_local ( def_id) {
1266
- let body = self . tcx . hir ( ) . body ( * body_id) ;
1267
- let msg = "use parentheses to call the function" ;
1268
- let snippet = format ! (
1269
- "{}({})" ,
1270
- ident,
1271
- body. params. iter( )
1272
- . map( |arg| match & arg. pat. kind {
1273
- hir:: PatKind :: Binding ( _, _, ident, None )
1274
- if ident. name != kw:: SelfLower => ident. to_string( ) ,
1275
- _ => "_" . to_string( ) ,
1276
- } ) . collect:: <Vec <_>>( ) . join( ", " ) ,
1277
- ) ;
1278
- // When the obligation error has been ensured to have been caused by
1279
- // an argument, the `obligation.cause.span` points at the expression
1280
- // of the argument, so we can provide a suggestion. This is signaled
1281
- // by `points_at_arg`. Otherwise, we give a more general note.
1282
- if points_at_arg {
1283
- err. span_suggestion (
1284
- obligation. cause . span ,
1285
- msg,
1286
- snippet,
1287
- Applicability :: HasPlaceholders ,
1288
- ) ;
1289
- } else {
1290
- err. help ( & format ! ( "{}: `{}`" , msg, snippet) ) ;
1291
- }
1292
- }
1246
+ ( def_id, self_ty. fn_sig ( self . tcx ) . output ( ) , "function" )
1247
+ }
1248
+ _ => return ,
1249
+ } ;
1250
+ let msg = format ! ( "use parentheses to call the {}" , callable) ;
1251
+ // We tried to apply the bound to an `fn` or closure. Check whether calling it would
1252
+ // evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
1253
+ // it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
1254
+
1255
+ let new_trait_ref = ty:: TraitRef {
1256
+ def_id : trait_ref. def_id ( ) ,
1257
+ substs : self . tcx . mk_substs_trait ( output_ty. skip_binder ( ) , & [ ] ) ,
1258
+ } ;
1259
+ let obligation = Obligation :: new (
1260
+ obligation. cause . clone ( ) ,
1261
+ obligation. param_env ,
1262
+ new_trait_ref. to_predicate ( ) ,
1263
+ ) ;
1264
+ let get_name = |err : & mut DiagnosticBuilder < ' _ > , kind : & hir:: PatKind | -> Option < String > {
1265
+ // Get the local name of this closure. This can be inaccurate because
1266
+ // of the possibility of reassignment, but this should be good enough.
1267
+ match & kind {
1268
+ hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , _, name, None ) => {
1269
+ Some ( format ! ( "{}" , name) )
1270
+ }
1271
+ _ => {
1272
+ err. note ( & msg) ;
1273
+ None
1274
+ }
1275
+ }
1276
+ } ;
1277
+ match self . evaluate_obligation ( & obligation) {
1278
+ Ok ( EvaluationResult :: EvaluatedToOk ) |
1279
+ Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) |
1280
+ Ok ( EvaluationResult :: EvaluatedToAmbig ) => {
1281
+ let hir = self . tcx . hir ( ) ;
1282
+ // Get the name of the callable and the arguments to be used in the suggestion.
1283
+ let snippet = match hir. get_if_local ( def_id) {
1284
+ Some ( hir:: Node :: Expr ( hir:: Expr {
1285
+ kind : hir:: ExprKind :: Closure ( _, decl, _, span, ..) ,
1286
+ ..
1287
+ } ) ) => {
1288
+ err. span_label ( * span, "consider calling this closure" ) ;
1289
+ let hir_id = match hir. as_local_hir_id ( def_id) {
1290
+ Some ( hir_id) => hir_id,
1291
+ None => return ,
1292
+ } ;
1293
+ let parent_node = hir. get_parent_node ( hir_id) ;
1294
+ let name = match hir. find ( parent_node) {
1295
+ Some ( hir:: Node :: Stmt ( hir:: Stmt {
1296
+ kind : hir:: StmtKind :: Local ( local) , ..
1297
+ } ) ) => match get_name ( err, & local. pat . kind ) {
1298
+ Some ( name) => name,
1299
+ None => return ,
1300
+ } ,
1301
+ // Different to previous arm because one is `&hir::Local` and the other
1302
+ // is `P<hir::Local>`.
1303
+ Some ( hir:: Node :: Local ( local) ) => match get_name ( err, & local. pat . kind ) {
1304
+ Some ( name) => name,
1305
+ None => return ,
1306
+ } ,
1307
+ _ => return ,
1308
+ } ;
1309
+ let args = decl. inputs . iter ( )
1310
+ . map ( |_| "_" )
1311
+ . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1312
+ format ! ( "{}({})" , name, args)
1313
+ }
1314
+ Some ( hir:: Node :: Item ( hir:: Item {
1315
+ ident,
1316
+ kind : hir:: ItemKind :: Fn ( .., body_id) ,
1317
+ ..
1318
+ } ) ) => {
1319
+ err. span_label ( ident. span , "consider calling this function" ) ;
1320
+ let body = hir. body ( * body_id) ;
1321
+ let args = body. params . iter ( )
1322
+ . map ( |arg| match & arg. pat . kind {
1323
+ hir:: PatKind :: Binding ( _, _, ident, None )
1324
+ if ident. name != kw:: SelfLower => ident. to_string ( ) ,
1325
+ _ => "_" . to_string ( ) ,
1326
+ } ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1327
+ format ! ( "{}({})" , ident, args)
1293
1328
}
1294
- _ => { }
1329
+ _ => return ,
1330
+ } ;
1331
+ if points_at_arg {
1332
+ // When the obligation error has been ensured to have been caused by
1333
+ // an argument, the `obligation.cause.span` points at the expression
1334
+ // of the argument, so we can provide a suggestion. This is signaled
1335
+ // by `points_at_arg`. Otherwise, we give a more general note.
1336
+ err. span_suggestion (
1337
+ obligation. cause . span ,
1338
+ & msg,
1339
+ snippet,
1340
+ Applicability :: HasPlaceholders ,
1341
+ ) ;
1342
+ } else {
1343
+ err. help ( & format ! ( "{}: `{}`" , msg, snippet) ) ;
1295
1344
}
1296
1345
}
1297
1346
_ => { }
0 commit comments