@@ -19,28 +19,10 @@ use syntax_pos::{self, Span};
19
19
use rustc:: hir;
20
20
use rustc:: ty:: { self , ImplOrTraitItem } ;
21
21
22
- use hir:: def_id:: DefId ;
23
-
24
22
use std:: rc:: Rc ;
25
23
26
24
use super :: method:: probe;
27
25
28
- struct MethodInfo < ' tcx > {
29
- ast : Option < ast:: Attribute > ,
30
- id : DefId ,
31
- item : Rc < ImplOrTraitItem < ' tcx > > ,
32
- }
33
-
34
- impl < ' tcx > MethodInfo < ' tcx > {
35
- fn new ( ast : Option < ast:: Attribute > , id : DefId , item : Rc < ImplOrTraitItem < ' tcx > > ) -> MethodInfo {
36
- MethodInfo {
37
- ast : ast,
38
- id : id,
39
- item : item,
40
- }
41
- }
42
- }
43
-
44
26
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
45
27
// Requires that the two types unify, and prints an error message if
46
28
// they don't.
@@ -79,41 +61,70 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
79
61
}
80
62
}
81
63
64
+ fn check_ref ( & self , expr : & hir:: Expr , checked_ty : Ty < ' tcx > ,
65
+ expected : Ty < ' tcx > ) -> Option < String > {
66
+ match ( & checked_ty. sty , & expected. sty ) {
67
+ ( & ty:: TyRef ( _, x_mutability) , & ty:: TyRef ( _, y_mutability) ) => {
68
+ // check if there is a mutability difference
69
+ if x_mutability. mutbl == hir:: Mutability :: MutImmutable &&
70
+ x_mutability. mutbl != y_mutability. mutbl &&
71
+ self . can_sub_types ( & x_mutability. ty , y_mutability. ty ) . is_ok ( ) {
72
+ if let Ok ( src) = self . tcx . sess . codemap ( ) . span_to_snippet ( expr. span ) {
73
+ return Some ( format ! ( "try with `&mut {}`" , & src. replace( "&" , "" ) ) ) ;
74
+ }
75
+ }
76
+ None
77
+ }
78
+ ( _, & ty:: TyRef ( _, mutability) ) => {
79
+ // check if it can work when put into a ref
80
+ let ref_ty = match mutability. mutbl {
81
+ hir:: Mutability :: MutMutable => self . tcx . mk_mut_ref (
82
+ self . tcx . mk_region ( ty:: ReStatic ) ,
83
+ checked_ty) ,
84
+ hir:: Mutability :: MutImmutable => self . tcx . mk_imm_ref (
85
+ self . tcx . mk_region ( ty:: ReStatic ) ,
86
+ checked_ty) ,
87
+ } ;
88
+ if self . try_coerce ( expr, ref_ty, expected) . is_ok ( ) {
89
+ if let Ok ( src) = self . tcx . sess . codemap ( ) . span_to_snippet ( expr. span ) {
90
+ return Some ( format ! ( "try with `{}{}`" ,
91
+ match mutability. mutbl {
92
+ hir:: Mutability :: MutMutable => "&mut " ,
93
+ hir:: Mutability :: MutImmutable => "&" ,
94
+ } ,
95
+ & src) ) ;
96
+ }
97
+ }
98
+ None
99
+ }
100
+ _ => None ,
101
+ }
102
+ }
103
+
82
104
// Checks that the type of `expr` can be coerced to `expected`.
83
105
pub fn demand_coerce( & self , expr : & hir:: Expr , checked_ty : Ty < ' tcx > , expected : Ty < ' tcx > ) {
84
106
let expected = self . resolve_type_vars_with_obligations ( expected) ;
85
107
if let Err ( e) = self . try_coerce ( expr, checked_ty, expected) {
86
108
let cause = self . misc ( expr. span ) ;
87
109
let expr_ty = self . resolve_type_vars_with_obligations ( checked_ty) ;
88
110
let mode = probe:: Mode :: MethodCall ;
89
- let suggestions =
90
- if let Ok ( methods) = self . probe_return ( syntax_pos:: DUMMY_SP , mode, expected,
91
- checked_ty, ast:: DUMMY_NODE_ID ) {
111
+ let suggestions = if let Some ( s) = self . check_ref ( expr, checked_ty, expected) {
112
+ Some ( s)
113
+ } else if let Ok ( methods) = self . probe_return ( syntax_pos:: DUMMY_SP ,
114
+ mode,
115
+ expected,
116
+ checked_ty,
117
+ ast:: DUMMY_NODE_ID ) {
92
118
let suggestions: Vec < _ > =
93
119
methods. iter ( )
94
- . filter_map ( |ref x| {
95
- if let Some ( id) = self . get_impl_id ( & x. item ) {
96
- Some ( MethodInfo :: new ( None , id, Rc :: new ( x. item . clone ( ) ) ) )
97
- } else {
98
- None
99
- } } )
120
+ . map ( |ref x| {
121
+ Rc :: new ( x. item . clone ( ) )
122
+ } )
100
123
. collect ( ) ;
101
124
if suggestions. len ( ) > 0 {
102
- let safe_suggestions: Vec < _ > =
103
- suggestions. iter ( )
104
- . map ( |ref x| MethodInfo :: new (
105
- self . find_attr ( x. id , "safe_suggestion" ) ,
106
- x. id ,
107
- x. item . clone ( ) ) )
108
- . filter ( |ref x| x. ast . is_some ( ) )
109
- . collect ( ) ;
110
- Some ( if safe_suggestions. len ( ) > 0 {
111
- self . get_best_match ( & safe_suggestions)
112
- } else {
113
- format ! ( "no safe suggestion found, here are functions which match your \
114
- needs but be careful:\n - {}",
115
- self . get_best_match( & suggestions) )
116
- } )
125
+ Some ( format ! ( "here are some functions which \
126
+ might fulfill your needs:\n - {}",
127
+ self . get_best_match( & suggestions) ) )
117
128
} else {
118
129
None
119
130
}
@@ -132,34 +143,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
132
143
}
133
144
}
134
145
135
- fn get_best_match ( & self , methods : & [ MethodInfo < ' tcx > ] ) -> String {
146
+ fn get_best_match ( & self , methods : & [ Rc < ImplOrTraitItem < ' tcx > > ] ) -> String {
136
147
if methods. len ( ) == 1 {
137
- return format ! ( " - {}" , methods[ 0 ] . item . name( ) ) ;
148
+ return format ! ( " - {}" , methods[ 0 ] . name( ) ) ;
138
149
}
139
- let no_argument_methods : Vec < & MethodInfo > =
150
+ let no_argument_methods : Vec < & Rc < ImplOrTraitItem < ' tcx > > > =
140
151
methods. iter( )
141
- . filter( |ref x| self . has_not_input_arg ( & * x. item ) )
152
+ . filter( |ref x| self . has_not_input_arg ( & * x) )
142
153
. collect( ) ;
143
154
if no_argument_methods. len( ) > 0 {
144
155
no_argument_methods. iter( )
145
- . map( |method| format ! ( "{}" , method. item. name( ) ) )
156
+ . take( 5 )
157
+ . map( |method| format ! ( "{}" , method. name( ) ) )
146
158
. collect :: < Vec < String > > ( )
147
159
. join( "\n - " )
148
160
} else {
149
161
methods. iter( )
150
- . map( |method| format ! ( "{}" , method. item. name( ) ) )
162
+ . take( 5 )
163
+ . map( |method| format ! ( "{}" , method. name( ) ) )
151
164
. collect :: < Vec < String > > ( )
152
165
. join( "\n - " )
153
166
}
154
167
}
155
168
156
- fn get_impl_id( & self , impl_: & ImplOrTraitItem < ' tcx > ) -> Option < DefId > {
157
- match * impl_ {
158
- ty : : ImplOrTraitItem :: MethodTraitItem ( ref m) => Some ( ( * m) . def_id) ,
159
- _ => None,
160
- }
161
- }
162
-
163
169
fn has_not_input_arg( & self , method: & ImplOrTraitItem < ' tcx > ) -> bool {
164
170
match * method {
165
171
ImplOrTraitItem : : MethodTraitItem ( ref x) => {
0 commit comments