@@ -1245,6 +1245,60 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12451245 }
12461246 }
12471247
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`.
12481302 fn suggest_fn_call (
12491303 & self ,
12501304 obligation : & PredicateObligation < ' tcx > ,
@@ -1253,63 +1307,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12531307 points_at_arg : bool ,
12541308 ) {
12551309 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+ }
12571314 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 ,
12661345 } ;
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)
13111370 }
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) ) ;
13131386 }
13141387 }
13151388
@@ -1410,12 +1483,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14101483 if let ty:: Ref ( _, t_type, _) = trait_type. kind {
14111484 trait_type = t_type;
14121485
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 ,
14161489 ObligationCause :: dummy ( ) ,
14171490 obligation. param_env ,
1418- new_trait_ref. to_predicate ( ) ,
14191491 ) ;
14201492
14211493 if self . predicate_may_hold ( & new_obligation) {
@@ -1473,12 +1545,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14731545 hir:: Mutability :: Immutable => self . tcx . mk_mut_ref ( region, t_type) ,
14741546 } ;
14751547
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 ,
14791551 ObligationCause :: dummy ( ) ,
14801552 obligation. param_env ,
1481- new_trait_ref. to_predicate ( ) ,
14821553 ) ;
14831554
14841555 if self . evaluate_obligation_no_overflow (
0 commit comments