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 > {
@@ -657,19 +658,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
657658 span,
658659 E0277 ,
659660 "{}" ,
660- message. unwrap_or_else( ||
661- format!( "the trait bound `{}` is not satisfied{}" ,
662- trait_ref. to_predicate( ) , post_message)
663- ) ) ;
661+ message. unwrap_or_else( || format!(
662+ "the trait bound `{}` is not satisfied{}" ,
663+ trait_ref. to_predicate( ) ,
664+ post_message,
665+ ) ) ) ;
664666
665667 let explanation =
666668 if obligation. cause . code == ObligationCauseCode :: MainFunctionType {
667669 "consider using `()`, or a `Result`" . to_owned ( )
668670 } else {
669- format ! ( "{}the trait `{}` is not implemented for `{}`" ,
670- pre_message,
671- trait_ref,
672- trait_ref. self_ty( ) )
671+ format ! (
672+ "{}the trait `{}` is not implemented for `{}`" ,
673+ pre_message,
674+ trait_ref,
675+ trait_ref. self_ty( ) ,
676+ )
673677 } ;
674678
675679 if let Some ( ref s) = label {
@@ -686,6 +690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
686690 }
687691
688692 self . suggest_borrow_on_unsized_slice ( & obligation. cause . code , & mut err) ;
693+ self . suggest_fn_call ( & obligation, & mut err, & trait_ref) ;
689694 self . suggest_remove_reference ( & obligation, & mut err, & trait_ref) ;
690695 self . suggest_semicolon_removal ( & obligation, & mut err, span, & trait_ref) ;
691696
@@ -953,6 +958,57 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
953958 }
954959 }
955960
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 whether calling it would evaluate
971+ // to a type that *would* satisfy the trait binding. If it would, suggest calling
972+ // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is
973+ // `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+ "use parentheses to call the function: `{}({})`" ,
996+ ident,
997+ body. params. iter( )
998+ . map( |arg| match & arg. pat. node {
999+ hir:: PatKind :: Binding ( _, _, ident, None )
1000+ if ident. name != kw:: SelfLower => ident. to_string( ) ,
1001+ _ => "_" . to_string( ) ,
1002+ } ) . collect:: <Vec <_>>( ) . join( ", " ) ) ) ;
1003+ }
1004+ }
1005+ _ => { }
1006+ }
1007+ }
1008+ _ => { }
1009+ }
1010+ }
1011+
9561012 /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
9571013 /// suggest removing these references until we reach a type that implements the trait.
9581014 fn suggest_remove_reference (
@@ -1535,25 +1591,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15351591 err. note ( "only the last element of a tuple may have a dynamically sized type" ) ;
15361592 }
15371593 ObligationCauseCode :: ProjectionWf ( data) => {
1538- err. note ( & format ! ( "required so that the projection `{}` is well-formed" ,
1539- data) ) ;
1594+ err. note ( & format ! (
1595+ "required so that the projection `{}` is well-formed" ,
1596+ data,
1597+ ) ) ;
15401598 }
15411599 ObligationCauseCode :: ReferenceOutlivesReferent ( ref_ty) => {
1542- err. note ( & format ! ( "required so that reference `{}` does not outlive its referent" ,
1543- ref_ty) ) ;
1600+ err. note ( & format ! (
1601+ "required so that reference `{}` does not outlive its referent" ,
1602+ ref_ty,
1603+ ) ) ;
15441604 }
15451605 ObligationCauseCode :: ObjectTypeBound ( object_ty, region) => {
1546- err. note ( & format ! ( "required so that the lifetime bound of `{}` for `{}` \
1547- is satisfied",
1548- region, object_ty) ) ;
1606+ err. note ( & format ! (
1607+ "required so that the lifetime bound of `{}` for `{}` is satisfied" ,
1608+ region,
1609+ object_ty,
1610+ ) ) ;
15491611 }
15501612 ObligationCauseCode :: ItemObligation ( item_def_id) => {
15511613 let item_name = tcx. def_path_str ( item_def_id) ;
15521614 let msg = format ! ( "required by `{}`" , item_name) ;
15531615
15541616 if let Some ( sp) = tcx. hir ( ) . span_if_local ( item_def_id) {
15551617 let sp = tcx. sess . source_map ( ) . def_span ( sp) ;
1556- err. span_note ( sp, & msg) ;
1618+ err. span_label ( sp, & msg) ;
15571619 } else {
15581620 err. note ( & msg) ;
15591621 }
0 commit comments