@@ -23,11 +23,13 @@ use rustc::infer::type_variable::TypeVariableOrigin;
2323use rustc:: util:: nodemap:: FxHashSet ;
2424use rustc:: infer:: { self , InferOk } ;
2525use syntax:: ast;
26+ use syntax:: util:: lev_distance:: lev_distance;
2627use syntax_pos:: Span ;
2728use rustc:: hir;
2829use std:: mem;
2930use std:: ops:: Deref ;
3031use std:: rc:: Rc ;
32+ use std:: cmp:: max;
3133
3234use self :: CandidateKind :: * ;
3335pub use self :: PickKind :: * ;
@@ -51,6 +53,10 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
5153 /// used for error reporting
5254 static_candidates : Vec < CandidateSource > ,
5355
56+ /// When probing for names, include names that are close to the
57+ /// requested name (by Levensthein distance)
58+ allow_similar_names : bool ,
59+
5460 /// Some(candidate) if there is a private candidate
5561 private_candidate : Option < Def > ,
5662
@@ -240,6 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
240246 Some ( steps) => steps,
241247 None => {
242248 return Err ( MethodError :: NoMatch ( NoMatchData :: new ( Vec :: new ( ) ,
249+ Vec :: new ( ) ,
243250 Vec :: new ( ) ,
244251 Vec :: new ( ) ,
245252 mode) ) )
@@ -261,7 +268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
261268 // that we create during the probe process are removed later
262269 self . probe ( |_| {
263270 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) ) ;
265272
266273 probe_cx. assemble_inherent_candidates ( ) ;
267274 match scope {
@@ -333,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
333340 mode : Mode ,
334341 method_name : Option < ast:: Name > ,
335342 return_type : Option < Ty < ' tcx > > ,
336- steps : Vec < CandidateStep < ' tcx > > )
343+ steps : Rc < Vec < CandidateStep < ' tcx > > > )
337344 -> ProbeContext < ' a , ' gcx , ' tcx > {
338345 ProbeContext {
339346 fcx,
@@ -344,8 +351,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
344351 inherent_candidates : Vec :: new ( ) ,
345352 extension_candidates : Vec :: new ( ) ,
346353 impl_dups : FxHashSet ( ) ,
347- steps : Rc :: new ( steps) ,
354+ steps : steps,
348355 static_candidates : Vec :: new ( ) ,
356+ allow_similar_names : false ,
349357 private_candidate : None ,
350358 unsatisfied_predicates : Vec :: new ( ) ,
351359 }
@@ -798,8 +806,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
798806 if let Some ( def) = private_candidate {
799807 return Err ( MethodError :: PrivateMatch ( def, out_of_scope_traits) ) ;
800808 }
809+ let lev_candidates = self . probe_for_lev_candidates ( ) ?;
801810
802811 Err ( MethodError :: NoMatch ( NoMatchData :: new ( static_candidates,
812+ lev_candidates,
803813 unsatisfied_predicates,
804814 out_of_scope_traits,
805815 self . mode ) ) )
@@ -913,11 +923,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
913923 debug ! ( "applicable_candidates: {:?}" , applicable_candidates) ;
914924
915925 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) ) ;
921928 }
922929 }
923930
@@ -1126,6 +1133,39 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
11261133 } )
11271134 }
11281135
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+
11291169 ///////////////////////////////////////////////////////////////////////////
11301170 // MISCELLANY
11311171 fn has_applicable_self ( & self , item : & ty:: AssociatedItem ) -> bool {
@@ -1253,10 +1293,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
12531293 self . tcx . erase_late_bound_regions ( value)
12541294 }
12551295
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.
12571298 fn impl_or_trait_item ( & self , def_id : DefId ) -> Vec < ty:: AssociatedItem > {
12581299 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+ }
12601311 } else {
12611312 self . tcx . associated_items ( def_id) . collect ( )
12621313 }
0 commit comments