@@ -23,11 +23,13 @@ use rustc::infer::type_variable::TypeVariableOrigin;
23
23
use rustc:: util:: nodemap:: FxHashSet ;
24
24
use rustc:: infer:: { self , InferOk } ;
25
25
use syntax:: ast;
26
+ use syntax:: util:: lev_distance:: lev_distance;
26
27
use syntax_pos:: Span ;
27
28
use rustc:: hir;
28
29
use std:: mem;
29
30
use std:: ops:: Deref ;
30
31
use std:: rc:: Rc ;
32
+ use std:: cmp:: max;
31
33
32
34
use self :: CandidateKind :: * ;
33
35
pub use self :: PickKind :: * ;
@@ -51,6 +53,10 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
51
53
/// used for error reporting
52
54
static_candidates : Vec < CandidateSource > ,
53
55
56
+ /// When probing for names, include names that are close to the
57
+ /// requested name (by Levensthein distance)
58
+ allow_similar_names : bool ,
59
+
54
60
/// Some(candidate) if there is a private candidate
55
61
private_candidate : Option < Def > ,
56
62
@@ -240,6 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
240
246
Some ( steps) => steps,
241
247
None => {
242
248
return Err ( MethodError :: NoMatch ( NoMatchData :: new ( Vec :: new ( ) ,
249
+ Vec :: new ( ) ,
243
250
Vec :: new ( ) ,
244
251
Vec :: new ( ) ,
245
252
mode) ) )
@@ -261,7 +268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
261
268
// that we create during the probe process are removed later
262
269
self . probe ( |_| {
263
270
let mut probe_cx =
264
- ProbeContext :: new ( self , span, mode, method_name, return_type, steps) ;
271
+ ProbeContext :: new ( self , span, mode, method_name, return_type, Rc :: new ( steps) ) ;
265
272
266
273
probe_cx. assemble_inherent_candidates ( ) ;
267
274
match scope {
@@ -333,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
333
340
mode : Mode ,
334
341
method_name : Option < ast:: Name > ,
335
342
return_type : Option < Ty < ' tcx > > ,
336
- steps : Vec < CandidateStep < ' tcx > > )
343
+ steps : Rc < Vec < CandidateStep < ' tcx > > > )
337
344
-> ProbeContext < ' a , ' gcx , ' tcx > {
338
345
ProbeContext {
339
346
fcx,
@@ -344,8 +351,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
344
351
inherent_candidates : Vec :: new ( ) ,
345
352
extension_candidates : Vec :: new ( ) ,
346
353
impl_dups : FxHashSet ( ) ,
347
- steps : Rc :: new ( steps) ,
354
+ steps : steps,
348
355
static_candidates : Vec :: new ( ) ,
356
+ allow_similar_names : false ,
349
357
private_candidate : None ,
350
358
unsatisfied_predicates : Vec :: new ( ) ,
351
359
}
@@ -798,8 +806,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
798
806
if let Some ( def) = private_candidate {
799
807
return Err ( MethodError :: PrivateMatch ( def, out_of_scope_traits) ) ;
800
808
}
809
+ let lev_candidates = self . probe_for_lev_candidates ( ) ?;
801
810
802
811
Err ( MethodError :: NoMatch ( NoMatchData :: new ( static_candidates,
812
+ lev_candidates,
803
813
unsatisfied_predicates,
804
814
out_of_scope_traits,
805
815
self . mode ) ) )
@@ -913,11 +923,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
913
923
debug ! ( "applicable_candidates: {:?}" , applicable_candidates) ;
914
924
915
925
if applicable_candidates. len ( ) > 1 {
916
- match self . collapse_candidates_to_trait_pick ( & applicable_candidates[ ..] ) {
917
- Some ( pick) => {
918
- return Some ( Ok ( pick) ) ;
919
- }
920
- None => { }
926
+ if let Some ( pick) = self . collapse_candidates_to_trait_pick ( & applicable_candidates[ ..] ) {
927
+ return Some ( Ok ( pick) ) ;
921
928
}
922
929
}
923
930
@@ -1126,6 +1133,39 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
1126
1133
} )
1127
1134
}
1128
1135
1136
+ /// Similarly to `probe_for_return_type`, this method attempts to find candidate methods where
1137
+ /// the method name may have been misspelt.
1138
+ fn probe_for_lev_candidates ( & mut self ) -> Result < Vec < ty:: AssociatedItem > , MethodError < ' tcx > > {
1139
+ debug ! ( "Probing for method names similar to {:?}" ,
1140
+ self . method_name) ;
1141
+
1142
+ let steps = self . steps . clone ( ) ;
1143
+ self . probe ( |_| {
1144
+ let mut pcx = ProbeContext :: new ( self . fcx , self . span , self . mode , self . method_name ,
1145
+ self . return_type , steps) ;
1146
+ pcx. allow_similar_names = true ;
1147
+ pcx. assemble_inherent_candidates ( ) ;
1148
+ pcx. assemble_extension_candidates_for_traits_in_scope ( ast:: DUMMY_NODE_ID ) ?;
1149
+
1150
+ let method_names = pcx. candidate_method_names ( ) ;
1151
+ pcx. allow_similar_names = false ;
1152
+ Ok ( method_names
1153
+ . iter ( )
1154
+ . filter_map ( |& method_name| {
1155
+ pcx. reset ( ) ;
1156
+ pcx. method_name = Some ( method_name) ;
1157
+ pcx. assemble_inherent_candidates ( ) ;
1158
+ pcx. assemble_extension_candidates_for_traits_in_scope ( ast:: DUMMY_NODE_ID )
1159
+ . ok ( ) . map_or ( None , |_| {
1160
+ pcx. pick_core ( )
1161
+ . and_then ( |pick| pick. ok ( ) )
1162
+ . and_then ( |pick| Some ( pick. item ) )
1163
+ } )
1164
+ } )
1165
+ . collect ( ) )
1166
+ } )
1167
+ }
1168
+
1129
1169
///////////////////////////////////////////////////////////////////////////
1130
1170
// MISCELLANY
1131
1171
fn has_applicable_self ( & self , item : & ty:: AssociatedItem ) -> bool {
@@ -1253,10 +1293,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
1253
1293
self . tcx . erase_late_bound_regions ( value)
1254
1294
}
1255
1295
1256
- /// Find the method with the appropriate name (or return type, as the case may be).
1296
+ /// Find the method with the appropriate name (or return type, as the case may be). If
1297
+ /// `allow_similar_names` is set, find methods with close-matching names.
1257
1298
fn impl_or_trait_item ( & self , def_id : DefId ) -> Vec < ty:: AssociatedItem > {
1258
1299
if let Some ( name) = self . method_name {
1259
- self . fcx . associated_item ( def_id, name) . map_or ( Vec :: new ( ) , |x| vec ! [ x] )
1300
+ if self . allow_similar_names {
1301
+ let max_dist = max ( name. as_str ( ) . len ( ) , 3 ) / 3 ;
1302
+ self . tcx . associated_items ( def_id)
1303
+ . filter ( |x| {
1304
+ let dist = lev_distance ( & * name. as_str ( ) , & x. name . as_str ( ) ) ;
1305
+ dist > 0 && dist <= max_dist
1306
+ } )
1307
+ . collect ( )
1308
+ } else {
1309
+ self . fcx . associated_item ( def_id, name) . map_or ( Vec :: new ( ) , |x| vec ! [ x] )
1310
+ }
1260
1311
} else {
1261
1312
self . tcx . associated_items ( def_id) . collect ( )
1262
1313
}
0 commit comments