@@ -14,8 +14,13 @@ use rustc::ty::Ty;
14
14
use rustc:: infer:: { InferOk } ;
15
15
use rustc:: traits:: ObligationCause ;
16
16
17
- use syntax_pos:: Span ;
17
+ use syntax:: ast;
18
+ use syntax_pos:: { self , Span } ;
18
19
use rustc:: hir;
20
+ use rustc:: hir:: def:: Def ;
21
+ use rustc:: ty:: { self , AssociatedItem } ;
22
+
23
+ use super :: method:: probe;
19
24
20
25
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
21
26
// Requires that the two types unify, and prints an error message if
@@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
27
32
self . register_predicates ( obligations) ;
28
33
} ,
29
34
Err ( e) => {
30
- self . report_mismatched_types ( & cause, expected, actual, e) ;
35
+ self . report_mismatched_types ( & cause, expected, actual, e) . emit ( ) ;
31
36
}
32
37
}
33
38
}
@@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46
51
self . register_predicates ( obligations) ;
47
52
} ,
48
53
Err ( e) => {
49
- self . report_mismatched_types ( cause, expected, actual, e) ;
54
+ self . report_mismatched_types ( cause, expected, actual, e) . emit ( ) ;
50
55
}
51
56
}
52
57
}
@@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
57
62
if let Err ( e) = self . try_coerce ( expr, checked_ty, expected) {
58
63
let cause = self . misc ( expr. span ) ;
59
64
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 ,
61
124
}
62
125
}
63
126
}
0 commit comments