@@ -14,8 +14,13 @@ use rustc::ty::Ty;
1414use rustc:: infer:: { InferOk } ;
1515use rustc:: traits:: ObligationCause ;
1616
17- use syntax_pos:: Span ;
17+ use syntax:: ast;
18+ use syntax_pos:: { self , Span } ;
1819use rustc:: hir;
20+ use rustc:: hir:: def:: Def ;
21+ use rustc:: ty:: { self , AssociatedItem } ;
22+
23+ use super :: method:: probe;
1924
2025impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
2126 // Requires that the two types unify, and prints an error message if
@@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2732 self . register_predicates ( obligations) ;
2833 } ,
2934 Err ( e) => {
30- self . report_mismatched_types ( & cause, expected, actual, e) ;
35+ self . report_mismatched_types ( & cause, expected, actual, e) . emit ( ) ;
3136 }
3237 }
3338 }
@@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4651 self . register_predicates ( obligations) ;
4752 } ,
4853 Err ( e) => {
49- self . report_mismatched_types ( cause, expected, actual, e) ;
54+ self . report_mismatched_types ( cause, expected, actual, e) . emit ( ) ;
5055 }
5156 }
5257 }
@@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5762 if let Err ( e) = self . try_coerce ( expr, checked_ty, expected) {
5863 let cause = self . misc ( expr. span ) ;
5964 let expr_ty = self . resolve_type_vars_with_obligations ( checked_ty) ;
60- self . report_mismatched_types ( & cause, expected, expr_ty, e) ;
65+ let mode = probe:: Mode :: MethodCall ;
66+ let suggestions = self . probe_for_return_type ( syntax_pos:: DUMMY_SP ,
67+ mode,
68+ expected,
69+ checked_ty,
70+ ast:: DUMMY_NODE_ID ) ;
71+ let mut err = self . report_mismatched_types ( & cause, expected, expr_ty, e) ;
72+ if suggestions. len ( ) > 0 {
73+ err. help ( & format ! ( "here are some functions which \
74+ might fulfill your needs:\n - {}",
75+ self . get_best_match( & suggestions) ) ) ;
76+ } ;
77+ err. emit ( ) ;
78+ }
79+ }
80+
81+ fn format_method_suggestion ( & self , method : & AssociatedItem ) -> String {
82+ format ! ( ".{}({})" ,
83+ method. name,
84+ if self . has_no_input_arg( method) {
85+ ""
86+ } else {
87+ "..."
88+ } )
89+ }
90+
91+ fn display_suggested_methods ( & self , methods : & [ AssociatedItem ] ) -> String {
92+ methods. iter ( )
93+ . take ( 5 )
94+ . map ( |method| self . format_method_suggestion ( & * method) )
95+ . collect :: < Vec < String > > ( )
96+ . join ( "\n - " )
97+ }
98+
99+ fn get_best_match ( & self , methods : & [ AssociatedItem ] ) -> String {
100+ let no_argument_methods: Vec < _ > =
101+ methods. iter ( )
102+ . filter ( |ref x| self . has_no_input_arg ( & * x) )
103+ . map ( |x| x. clone ( ) )
104+ . collect ( ) ;
105+ if no_argument_methods. len ( ) > 0 {
106+ self . display_suggested_methods ( & no_argument_methods)
107+ } else {
108+ self . display_suggested_methods ( & methods)
109+ }
110+ }
111+
112+ // This function checks if the method isn't static and takes other arguments than `self`.
113+ fn has_no_input_arg ( & self , method : & AssociatedItem ) -> bool {
114+ match method. def ( ) {
115+ Def :: Method ( def_id) => {
116+ match self . tcx . item_type ( def_id) . sty {
117+ ty:: TypeVariants :: TyFnDef ( _, _, fty) => {
118+ fty. sig . skip_binder ( ) . inputs ( ) . len ( ) == 1
119+ }
120+ _ => false ,
121+ }
122+ }
123+ _ => false ,
61124 }
62125 }
63126}
0 commit comments