@@ -150,19 +150,36 @@ pub enum Mode {
150
150
}
151
151
152
152
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
153
+ /// This is used to offer suggestions to users. It returns methods
154
+ /// that could have been called which have the desired return
155
+ /// type. Some effort is made to rule out methods that, if called,
156
+ /// would result in an error (basically, the same criteria we
157
+ /// would use to decide if a method is a plausible fit for
158
+ /// ambiguity purposes).
153
159
pub fn probe_for_return_type ( & self ,
154
160
span : Span ,
155
161
mode : Mode ,
156
162
return_type : Ty < ' tcx > ,
157
163
self_ty : Ty < ' tcx > ,
158
164
scope_expr_id : ast:: NodeId )
159
- -> PickResult < ' tcx > {
165
+ -> Vec < ty :: ImplOrTraitItem < ' tcx > > {
160
166
debug ! ( "probe(self_ty={:?}, return_type={}, scope_expr_id={})" ,
161
167
self_ty,
162
168
return_type,
163
169
scope_expr_id) ;
164
- self . probe_op ( span, mode, LookingFor :: ReturnType ( return_type) , self_ty, scope_expr_id,
165
- |probe_cx| probe_cx. pick ( ) )
170
+ let method_names =
171
+ self . probe_op ( span, mode, LookingFor :: ReturnType ( return_type) , self_ty, scope_expr_id,
172
+ |probe_cx| Ok ( probe_cx. candidate_method_names ( ) ) )
173
+ . unwrap_or ( vec ! [ ] ) ;
174
+ method_names
175
+ . iter ( )
176
+ . flat_map ( |& method_name| {
177
+ match self . probe_for_name ( span, mode, method_name, self_ty, scope_expr_id) {
178
+ Ok ( picks) => picks. into_iter ( ) . map ( move |pick| pick. item ) . collect ( ) ,
179
+ Err ( _) => vec ! [ ] ,
180
+ }
181
+ } )
182
+ . collect ( )
166
183
}
167
184
168
185
pub fn probe_for_name ( & self ,
@@ -184,15 +201,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
184
201
|probe_cx| probe_cx. pick ( ) )
185
202
}
186
203
187
- fn probe_op < ' a , OP , R > ( & ' a self ,
188
- span : Span ,
189
- mode : Mode ,
190
- looking_for : LookingFor < ' tcx > ,
191
- self_ty : Ty < ' tcx > ,
192
- scope_expr_id : ast:: NodeId ,
193
- op : OP )
194
- -> R
195
- where OP : FnOnce ( & mut ProbeContext < ' a , ' gcx , ' tcx > ) -> R
204
+ fn probe_op < OP , R > ( & ' a self ,
205
+ span : Span ,
206
+ mode : Mode ,
207
+ looking_for : LookingFor < ' tcx > ,
208
+ self_ty : Ty < ' tcx > ,
209
+ scope_expr_id : ast:: NodeId ,
210
+ op : OP )
211
+ -> Result < R , MethodError < ' tcx > >
212
+ where OP : FnOnce ( ProbeContext < ' a , ' gcx , ' tcx > ) -> Result < R , MethodError < ' tcx > >
196
213
{
197
214
// FIXME(#18741) -- right now, creating the steps involves evaluating the
198
215
// `*` operator, which registers obligations that then escape into
@@ -249,7 +266,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
249
266
steps, opt_simplified_steps) ;
250
267
probe_cx. assemble_inherent_candidates ( ) ;
251
268
probe_cx. assemble_extension_candidates_for_traits_in_scope ( scope_expr_id) ?;
252
- op ( & mut probe_cx)
269
+ op ( probe_cx)
253
270
} )
254
271
}
255
272
@@ -894,10 +911,30 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
894
911
}
895
912
}
896
913
914
+ fn candidate_method_names ( & self ) -> Vec < ast:: Name > {
915
+ let mut set = FnvHashSet ( ) ;
916
+ let mut names: Vec < _ > =
917
+ self . inherent_candidates
918
+ . iter ( )
919
+ . chain ( & self . extension_candidates )
920
+ . map ( |candidate| candidate. item . name ( ) )
921
+ . filter ( |& name| set. insert ( name) )
922
+ . collect ( ) ;
923
+
924
+ // sort them by the name so we have a stable result
925
+ names. sort_by_key ( |n| n. as_str ( ) ) ;
926
+ names
927
+ }
928
+
897
929
///////////////////////////////////////////////////////////////////////////
898
930
// THE ACTUAL SEARCH
899
931
900
932
fn pick ( mut self ) -> PickResult < ' tcx > {
933
+ assert ! ( match self . looking_for {
934
+ LookingFor :: MethodName ( _) => true ,
935
+ LookingFor :: ReturnType ( _) => false ,
936
+ } ) ;
937
+
901
938
if let Some ( ret) = self . pick_core ( ) {
902
939
return ret;
903
940
}
@@ -959,33 +996,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
959
996
fn pick_core ( & mut self ) -> Option < PickResult < ' tcx > > {
960
997
let steps = self . steps . clone ( ) ;
961
998
962
- match self . looking_for {
963
- LookingFor :: MethodName ( _) => {
964
- // find the first step that works
965
- steps. iter ( )
966
- . filter_map ( |step| self . pick_step ( step) )
967
- . next ( )
968
- }
969
- LookingFor :: ReturnType ( _) => {
970
- // Normally, we stop at the first step where we find a positive match.
971
- // But when we are scanning for methods with a suitable return type,
972
- // these methods have distinct names and hence may not shadow one another
973
- // (also, this is just for hints, so precision is less important).
974
- let mut ret = Vec :: new ( ) ;
975
-
976
- for step in steps. iter ( ) {
977
- match self . pick_step ( step) {
978
- Some ( Ok ( mut elems) ) => ret. append ( & mut elems) ,
979
- _ => { }
980
- }
981
- }
982
- if ret. len ( ) < 1 {
983
- None
984
- } else {
985
- Some ( Ok ( ret) )
986
- }
987
- }
988
- }
999
+ // find the first step that works
1000
+ steps. iter ( )
1001
+ . filter_map ( |step| self . pick_step ( step) )
1002
+ . next ( )
989
1003
}
990
1004
991
1005
fn pick_step ( & mut self , step : & CandidateStep < ' tcx > ) -> Option < PickResult < ' tcx > > {
0 commit comments