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