11use super :: {
2+ ConstEvalFailure ,
3+ EvaluationResult ,
24 FulfillmentError ,
35 FulfillmentErrorCode ,
46 MismatchedProjectionTypes ,
7+ ObjectSafetyViolation ,
58 Obligation ,
69 ObligationCause ,
710 ObligationCauseCode ,
811 OnUnimplementedDirective ,
912 OnUnimplementedNote ,
1013 OutputTypeParameterMismatch ,
11- TraitNotObjectSafe ,
12- ConstEvalFailure ,
14+ Overflow ,
1315 PredicateObligation ,
1416 SelectionContext ,
1517 SelectionError ,
16- ObjectSafetyViolation ,
17- Overflow ,
18+ TraitNotObjectSafe ,
1819} ;
1920
2021use crate :: hir;
@@ -35,7 +36,7 @@ use crate::util::nodemap::{FxHashMap, FxHashSet};
3536use errors:: { Applicability , DiagnosticBuilder } ;
3637use std:: fmt;
3738use syntax:: ast;
38- use syntax:: symbol:: sym;
39+ use syntax:: symbol:: { sym, kw } ;
3940use syntax_pos:: { DUMMY_SP , Span , ExpnKind } ;
4041
4142impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
@@ -669,8 +670,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
669670 } else {
670671 format ! (
671672 "{}the trait `{}` is not implemented for `{}`" ,
672- pre_message,
673- trait_ref,
673+ pre_message,
674+ trait_ref,
674675 trait_ref. self_ty( ) ,
675676 )
676677 } ;
@@ -689,6 +690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
689690 }
690691
691692 self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
693+ self . suggest_fn_call ( & obligation, & mut err, & trait_ref) ;
692694 self . suggest_remove_reference ( & obligation, & mut err, & trait_ref) ;
693695 self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
694696
@@ -956,6 +958,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
956958 }
957959 }
958960
961+ fn suggest_fn_call (
962+ & self ,
963+ obligation : & PredicateObligation < ' tcx > ,
964+ err : & mut DiagnosticBuilder < ' tcx > ,
965+ trait_ref : & ty:: Binder < ty:: TraitRef < ' tcx > > ,
966+ ) {
967+ let self_ty = trait_ref. self_ty ( ) ;
968+ match self_ty. sty {
969+ ty:: FnDef ( def_id, _) => {
970+ // We tried to apply the bound to an `fn`. Check wether calling it
971+ // would evaluate to a type that *would* satisfy the trait binding.
972+ // If it would, suggest calling it: `bar(foo)` -> `bar(foo)`. This
973+ // case is *very* to hit if `foo` is `async`.
974+ let output_ty = self_ty. fn_sig ( self . tcx ) . output ( ) ;
975+ let new_trait_ref = ty:: TraitRef {
976+ def_id : trait_ref. def_id ( ) ,
977+ substs : self . tcx . mk_substs_trait ( output_ty. skip_binder ( ) , & [ ] ) ,
978+ } ;
979+ let obligation = Obligation :: new (
980+ obligation. cause . clone ( ) ,
981+ obligation. param_env ,
982+ new_trait_ref. to_predicate ( ) ,
983+ ) ;
984+ match self . evaluate_obligation ( & obligation) {
985+ Ok ( EvaluationResult :: EvaluatedToOk ) |
986+ Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) |
987+ Ok ( EvaluationResult :: EvaluatedToAmbig ) => {
988+ if let Some ( hir:: Node :: Item ( hir:: Item {
989+ ident,
990+ node : hir:: ItemKind :: Fn ( .., body_id) ,
991+ ..
992+ } ) ) = self . tcx . hir ( ) . get_if_local ( def_id) {
993+ let body = self . tcx . hir ( ) . body ( * body_id) ;
994+ err. help ( & format ! (
995+ "it looks like you forgot to use parentheses to \
996+ call the function: `{}({})`",
997+ ident,
998+ body. arguments. iter( )
999+ . map( |arg| match & arg. pat. node {
1000+ hir:: PatKind :: Binding ( _, _, ident, None )
1001+ if ident. name != kw:: SelfLower => ident. to_string( ) ,
1002+ _ => "_" . to_string( ) ,
1003+ } ) . collect:: <Vec <_>>( ) . join( ", " ) ) ) ;
1004+ }
1005+ }
1006+ _ => { }
1007+ }
1008+ }
1009+ _ => { }
1010+ }
1011+ }
1012+
9591013 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
9601014 /// suggest removing these references until we reach a type that implements the trait.
9611015 fn suggest_remove_reference (
0 commit comments