1
1
use super :: {
2
+ ConstEvalFailure ,
3
+ EvaluationResult ,
2
4
FulfillmentError ,
3
5
FulfillmentErrorCode ,
4
6
MismatchedProjectionTypes ,
7
+ ObjectSafetyViolation ,
5
8
Obligation ,
6
9
ObligationCause ,
7
10
ObligationCauseCode ,
8
11
OnUnimplementedDirective ,
9
12
OnUnimplementedNote ,
10
13
OutputTypeParameterMismatch ,
11
- TraitNotObjectSafe ,
12
- ConstEvalFailure ,
14
+ Overflow ,
13
15
PredicateObligation ,
14
16
SelectionContext ,
15
17
SelectionError ,
16
- ObjectSafetyViolation ,
17
- Overflow ,
18
+ TraitNotObjectSafe ,
18
19
} ;
19
20
20
21
use crate :: hir;
@@ -35,7 +36,7 @@ use crate::util::nodemap::{FxHashMap, FxHashSet};
35
36
use errors:: { Applicability , DiagnosticBuilder } ;
36
37
use std:: fmt;
37
38
use syntax:: ast;
38
- use syntax:: symbol:: sym;
39
+ use syntax:: symbol:: { sym, kw } ;
39
40
use syntax_pos:: { DUMMY_SP , Span , ExpnKind } ;
40
41
41
42
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
@@ -669,8 +670,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
669
670
} else {
670
671
format ! (
671
672
"{}the trait `{}` is not implemented for `{}`" ,
672
- pre_message,
673
- trait_ref,
673
+ pre_message,
674
+ trait_ref,
674
675
trait_ref. self_ty( ) ,
675
676
)
676
677
} ;
@@ -689,6 +690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
689
690
}
690
691
691
692
self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
693
+ self . suggest_fn_call ( & obligation, & mut err, & trait_ref) ;
692
694
self . suggest_remove_reference ( & obligation, & mut err, & trait_ref) ;
693
695
self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
694
696
@@ -956,6 +958,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
956
958
}
957
959
}
958
960
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
+
959
1013
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
960
1014
/// suggest removing these references until we reach a type that implements the trait.
961
1015
fn suggest_remove_reference (
0 commit comments