@@ -1238,60 +1238,109 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12381238 points_at_arg : bool ,
12391239 ) {
12401240 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+ }
12421245 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)
12931328 }
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) ) ;
12951344 }
12961345 }
12971346 _ => { }
0 commit comments