@@ -1245,6 +1245,60 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1245
1245
}
1246
1246
}
1247
1247
1248
+ fn mk_obligation_for_def_id (
1249
+ & self ,
1250
+ def_id : DefId ,
1251
+ output_ty : Ty < ' tcx > ,
1252
+ cause : ObligationCause < ' tcx > ,
1253
+ param_env : ty:: ParamEnv < ' tcx > ,
1254
+ ) -> PredicateObligation < ' tcx > {
1255
+ let new_trait_ref = ty:: TraitRef {
1256
+ def_id,
1257
+ substs : self . tcx . mk_substs_trait ( output_ty, & [ ] ) ,
1258
+ } ;
1259
+ Obligation :: new ( cause, param_env, new_trait_ref. to_predicate ( ) )
1260
+ }
1261
+
1262
+ /// Given a closure's `DefId`, return the given name of the closure.
1263
+ ///
1264
+ /// This doesn't account for reassignments, but it's only used for suggestions.
1265
+ fn get_closure_name (
1266
+ & self ,
1267
+ def_id : DefId ,
1268
+ err : & mut DiagnosticBuilder < ' _ > ,
1269
+ msg : & str ,
1270
+ ) -> Option < String > {
1271
+ let get_name = |err : & mut DiagnosticBuilder < ' _ > , kind : & hir:: PatKind | -> Option < String > {
1272
+ // Get the local name of this closure. This can be inaccurate because
1273
+ // of the possibility of reassignment, but this should be good enough.
1274
+ match & kind {
1275
+ hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , _, name, None ) => {
1276
+ Some ( format ! ( "{}" , name) )
1277
+ }
1278
+ _ => {
1279
+ err. note ( & msg) ;
1280
+ None
1281
+ }
1282
+ }
1283
+ } ;
1284
+
1285
+ let hir = self . tcx . hir ( ) ;
1286
+ let hir_id = hir. as_local_hir_id ( def_id) ?;
1287
+ let parent_node = hir. get_parent_node ( hir_id) ;
1288
+ match hir. find ( parent_node) {
1289
+ Some ( hir:: Node :: Stmt ( hir:: Stmt {
1290
+ kind : hir:: StmtKind :: Local ( local) , ..
1291
+ } ) ) => get_name ( err, & local. pat . kind ) ,
1292
+ // Different to previous arm because one is `&hir::Local` and the other
1293
+ // is `P<hir::Local>`.
1294
+ Some ( hir:: Node :: Local ( local) ) => get_name ( err, & local. pat . kind ) ,
1295
+ _ => return None ,
1296
+ }
1297
+ }
1298
+
1299
+ /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
1300
+ /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
1301
+ /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
1248
1302
fn suggest_fn_call (
1249
1303
& self ,
1250
1304
obligation : & PredicateObligation < ' tcx > ,
@@ -1253,63 +1307,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1253
1307
points_at_arg : bool ,
1254
1308
) {
1255
1309
let self_ty = trait_ref. self_ty ( ) ;
1256
- match self_ty. kind {
1310
+ let ( def_id, output_ty, callable) = match self_ty. kind {
1311
+ ty:: Closure ( def_id, substs) => {
1312
+ ( def_id, self . closure_sig ( def_id, substs) . output ( ) , "closure" )
1313
+ }
1257
1314
ty:: FnDef ( def_id, _) => {
1258
- // We tried to apply the bound to an `fn`. Check whether calling it would evaluate
1259
- // to a type that *would* satisfy the trait binding. If it would, suggest calling
1260
- // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is
1261
- // `async`.
1262
- let output_ty = self_ty. fn_sig ( self . tcx ) . output ( ) ;
1263
- let new_trait_ref = ty:: TraitRef {
1264
- def_id : trait_ref. def_id ( ) ,
1265
- substs : self . tcx . mk_substs_trait ( output_ty. skip_binder ( ) , & [ ] ) ,
1315
+ ( def_id, self_ty. fn_sig ( self . tcx ) . output ( ) , "function" )
1316
+ }
1317
+ _ => return ,
1318
+ } ;
1319
+ let msg = format ! ( "use parentheses to call the {}" , callable) ;
1320
+
1321
+ let obligation = self . mk_obligation_for_def_id (
1322
+ trait_ref. def_id ( ) ,
1323
+ output_ty. skip_binder ( ) ,
1324
+ obligation. cause . clone ( ) ,
1325
+ obligation. param_env ,
1326
+ ) ;
1327
+
1328
+ match self . evaluate_obligation ( & obligation) {
1329
+ Ok ( EvaluationResult :: EvaluatedToOk ) |
1330
+ Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) |
1331
+ Ok ( EvaluationResult :: EvaluatedToAmbig ) => { }
1332
+ _ => return ,
1333
+ }
1334
+ let hir = self . tcx . hir ( ) ;
1335
+ // Get the name of the callable and the arguments to be used in the suggestion.
1336
+ let snippet = match hir. get_if_local ( def_id) {
1337
+ Some ( hir:: Node :: Expr ( hir:: Expr {
1338
+ kind : hir:: ExprKind :: Closure ( _, decl, _, span, ..) ,
1339
+ ..
1340
+ } ) ) => {
1341
+ err. span_label ( * span, "consider calling this closure" ) ;
1342
+ let name = match self . get_closure_name ( def_id, err, & msg) {
1343
+ Some ( name) => name,
1344
+ None => return ,
1266
1345
} ;
1267
- let obligation = Obligation :: new (
1268
- obligation. cause . clone ( ) ,
1269
- obligation. param_env ,
1270
- new_trait_ref. to_predicate ( ) ,
1271
- ) ;
1272
- match self . evaluate_obligation ( & obligation) {
1273
- Ok ( EvaluationResult :: EvaluatedToOk ) |
1274
- Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) |
1275
- Ok ( EvaluationResult :: EvaluatedToAmbig ) => {
1276
- if let Some ( hir:: Node :: Item ( hir:: Item {
1277
- ident,
1278
- kind : hir:: ItemKind :: Fn ( .., body_id) ,
1279
- ..
1280
- } ) ) = self . tcx . hir ( ) . get_if_local ( def_id) {
1281
- let body = self . tcx . hir ( ) . body ( * body_id) ;
1282
- let msg = "use parentheses to call the function" ;
1283
- let snippet = format ! (
1284
- "{}({})" ,
1285
- ident,
1286
- body. params. iter( )
1287
- . map( |arg| match & arg. pat. kind {
1288
- hir:: PatKind :: Binding ( _, _, ident, None )
1289
- if ident. name != kw:: SelfLower => ident. to_string( ) ,
1290
- _ => "_" . to_string( ) ,
1291
- } ) . collect:: <Vec <_>>( ) . join( ", " ) ,
1292
- ) ;
1293
- // When the obligation error has been ensured to have been caused by
1294
- // an argument, the `obligation.cause.span` points at the expression
1295
- // of the argument, so we can provide a suggestion. This is signaled
1296
- // by `points_at_arg`. Otherwise, we give a more general note.
1297
- if points_at_arg {
1298
- err. span_suggestion (
1299
- obligation. cause . span ,
1300
- msg,
1301
- snippet,
1302
- Applicability :: HasPlaceholders ,
1303
- ) ;
1304
- } else {
1305
- err. help ( & format ! ( "{}: `{}`" , msg, snippet) ) ;
1306
- }
1307
- }
1308
- }
1309
- _ => { }
1310
- }
1346
+ let args = decl. inputs . iter ( )
1347
+ . map ( |_| "_" )
1348
+ . collect :: < Vec < _ > > ( )
1349
+ . join ( ", " ) ;
1350
+ format ! ( "{}({})" , name, args)
1351
+ }
1352
+ Some ( hir:: Node :: Item ( hir:: Item {
1353
+ ident,
1354
+ kind : hir:: ItemKind :: Fn ( .., body_id) ,
1355
+ ..
1356
+ } ) ) => {
1357
+ err. span_label ( ident. span , "consider calling this function" ) ;
1358
+ let body = hir. body ( * body_id) ;
1359
+ let args = body. params . iter ( )
1360
+ . map ( |arg| match & arg. pat . kind {
1361
+ hir:: PatKind :: Binding ( _, _, ident, None )
1362
+ // FIXME: provide a better suggestion when encountering `SelfLower`, it
1363
+ // should suggest a method call.
1364
+ if ident. name != kw:: SelfLower => ident. to_string ( ) ,
1365
+ _ => "_" . to_string ( ) ,
1366
+ } )
1367
+ . collect :: < Vec < _ > > ( )
1368
+ . join ( ", " ) ;
1369
+ format ! ( "{}({})" , ident, args)
1311
1370
}
1312
- _ => { }
1371
+ _ => return ,
1372
+ } ;
1373
+ if points_at_arg {
1374
+ // When the obligation error has been ensured to have been caused by
1375
+ // an argument, the `obligation.cause.span` points at the expression
1376
+ // of the argument, so we can provide a suggestion. This is signaled
1377
+ // by `points_at_arg`. Otherwise, we give a more general note.
1378
+ err. span_suggestion (
1379
+ obligation. cause . span ,
1380
+ & msg,
1381
+ snippet,
1382
+ Applicability :: HasPlaceholders ,
1383
+ ) ;
1384
+ } else {
1385
+ err. help ( & format ! ( "{}: `{}`" , msg, snippet) ) ;
1313
1386
}
1314
1387
}
1315
1388
@@ -1410,12 +1483,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1410
1483
if let ty:: Ref ( _, t_type, _) = trait_type. kind {
1411
1484
trait_type = t_type;
1412
1485
1413
- let substs = self . tcx . mk_substs_trait ( trait_type , & [ ] ) ;
1414
- let new_trait_ref = ty :: TraitRef :: new ( trait_ref. def_id , substs ) ;
1415
- let new_obligation = Obligation :: new (
1486
+ let new_obligation = self . mk_obligation_for_def_id (
1487
+ trait_ref. def_id ,
1488
+ trait_type ,
1416
1489
ObligationCause :: dummy ( ) ,
1417
1490
obligation. param_env ,
1418
- new_trait_ref. to_predicate ( ) ,
1419
1491
) ;
1420
1492
1421
1493
if self . predicate_may_hold ( & new_obligation) {
@@ -1473,12 +1545,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1473
1545
hir:: Mutability :: Immutable => self . tcx . mk_mut_ref ( region, t_type) ,
1474
1546
} ;
1475
1547
1476
- let substs = self . tcx . mk_substs_trait ( & trait_type , & [ ] ) ;
1477
- let new_trait_ref = ty :: TraitRef :: new ( trait_ref. skip_binder ( ) . def_id , substs ) ;
1478
- let new_obligation = Obligation :: new (
1548
+ let new_obligation = self . mk_obligation_for_def_id (
1549
+ trait_ref. skip_binder ( ) . def_id ,
1550
+ trait_type ,
1479
1551
ObligationCause :: dummy ( ) ,
1480
1552
obligation. param_env ,
1481
- new_trait_ref. to_predicate ( ) ,
1482
1553
) ;
1483
1554
1484
1555
if self . evaluate_obligation_no_overflow (
0 commit comments