@@ -120,6 +120,16 @@ struct BindingError {
120120 target : BTreeSet < Span > ,
121121}
122122
123+ struct TypoSuggestion {
124+ candidate : Symbol ,
125+
126+ /// The kind of the binding ("crate", "module", etc.)
127+ kind : & ' static str ,
128+
129+ /// An appropriate article to refer to the binding ("a", "an", etc.)
130+ article : & ' static str ,
131+ }
132+
123133impl PartialOrd for BindingError {
124134 fn partial_cmp ( & self , other : & BindingError ) -> Option < cmp:: Ordering > {
125135 Some ( self . cmp ( other) )
@@ -1448,7 +1458,7 @@ impl PrimitiveTypeTable {
14481458 }
14491459}
14501460
1451- #[ derive( Default , Clone ) ]
1461+ #[ derive( Debug , Default , Clone ) ]
14521462pub struct ExternPreludeEntry < ' a > {
14531463 extern_crate_item : Option < & ' a NameBinding < ' a > > ,
14541464 pub introduced_by_item : bool ,
@@ -3291,8 +3301,19 @@ impl<'a> Resolver<'a> {
32913301 let mut levenshtein_worked = false ;
32923302
32933303 // Try Levenshtein algorithm.
3294- if let Some ( candidate) = this. lookup_typo_candidate ( path, ns, is_expected, span) {
3295- err. span_label ( ident_span, format ! ( "did you mean `{}`?" , candidate) ) ;
3304+ let suggestion = this. lookup_typo_candidate ( path, ns, is_expected, span) ;
3305+ if let Some ( suggestion) = suggestion {
3306+ let msg = format ! (
3307+ "{} {} with a similar name exists" ,
3308+ suggestion. article, suggestion. kind
3309+ ) ;
3310+ err. span_suggestion_with_applicability (
3311+ ident_span,
3312+ & msg,
3313+ suggestion. candidate . to_string ( ) ,
3314+ Applicability :: MaybeIncorrect ,
3315+ ) ;
3316+
32963317 levenshtein_worked = true ;
32973318 }
32983319
@@ -4183,19 +4204,25 @@ impl<'a> Resolver<'a> {
41834204 None
41844205 }
41854206
4186- fn lookup_typo_candidate < FilterFn > ( & mut self ,
4187- path : & [ Segment ] ,
4188- ns : Namespace ,
4189- filter_fn : FilterFn ,
4190- span : Span )
4191- -> Option < Symbol >
4192- where FilterFn : Fn ( Def ) -> bool
4207+ fn lookup_typo_candidate < FilterFn > (
4208+ & mut self ,
4209+ path : & [ Segment ] ,
4210+ ns : Namespace ,
4211+ filter_fn : FilterFn ,
4212+ span : Span ,
4213+ ) -> Option < TypoSuggestion >
4214+ where
4215+ FilterFn : Fn ( Def ) -> bool ,
41934216 {
4194- let add_module_candidates = |module : Module , names : & mut Vec < Name > | {
4217+ let add_module_candidates = |module : Module , names : & mut Vec < TypoSuggestion > | {
41954218 for ( & ( ident, _) , resolution) in module. resolutions . borrow ( ) . iter ( ) {
41964219 if let Some ( binding) = resolution. borrow ( ) . binding {
41974220 if filter_fn ( binding. def ( ) ) {
4198- names. push ( ident. name ) ;
4221+ names. push ( TypoSuggestion {
4222+ candidate : ident. name ,
4223+ article : binding. def ( ) . article ( ) ,
4224+ kind : binding. def ( ) . kind_name ( ) ,
4225+ } ) ;
41994226 }
42004227 }
42014228 }
@@ -4209,7 +4236,11 @@ impl<'a> Resolver<'a> {
42094236 // Locals and type parameters
42104237 for ( ident, def) in & rib. bindings {
42114238 if filter_fn ( * def) {
4212- names. push ( ident. name ) ;
4239+ names. push ( TypoSuggestion {
4240+ candidate : ident. name ,
4241+ article : def. article ( ) ,
4242+ kind : def. kind_name ( ) ,
4243+ } ) ;
42134244 }
42144245 }
42154246 // Items in scope
@@ -4222,7 +4253,13 @@ impl<'a> Resolver<'a> {
42224253 } else {
42234254 // Items from the prelude
42244255 if !module. no_implicit_prelude {
4225- names. extend ( self . extern_prelude . iter ( ) . map ( |( ident, _) | ident. name ) ) ;
4256+ names. extend ( self . extern_prelude . iter ( ) . map ( |( ident, _) | {
4257+ TypoSuggestion {
4258+ candidate : ident. name ,
4259+ article : "a" ,
4260+ kind : "crate" ,
4261+ }
4262+ } ) ) ;
42264263 if let Some ( prelude) = self . prelude {
42274264 add_module_candidates ( prelude, & mut names) ;
42284265 }
@@ -4234,7 +4271,13 @@ impl<'a> Resolver<'a> {
42344271 // Add primitive types to the mix
42354272 if filter_fn ( Def :: PrimTy ( Bool ) ) {
42364273 names. extend (
4237- self . primitive_type_table . primitive_types . iter ( ) . map ( |( name, _) | name)
4274+ self . primitive_type_table . primitive_types . iter ( ) . map ( |( name, _) | {
4275+ TypoSuggestion {
4276+ candidate : * name,
4277+ article : "a" ,
4278+ kind : "primitive type" ,
4279+ }
4280+ } )
42384281 )
42394282 }
42404283 } else {
@@ -4251,9 +4294,16 @@ impl<'a> Resolver<'a> {
42514294
42524295 let name = path[ path. len ( ) - 1 ] . ident . name ;
42534296 // Make sure error reporting is deterministic.
4254- names. sort_by_cached_key ( |name| name. as_str ( ) ) ;
4255- match find_best_match_for_name ( names. iter ( ) , & name. as_str ( ) , None ) {
4256- Some ( found) if found != name => Some ( found) ,
4297+ names. sort_by_cached_key ( |suggestion| suggestion. candidate . as_str ( ) ) ;
4298+
4299+ match find_best_match_for_name (
4300+ names. iter ( ) . map ( |suggestion| & suggestion. candidate ) ,
4301+ & name. as_str ( ) ,
4302+ None ,
4303+ ) {
4304+ Some ( found) if found != name => names
4305+ . into_iter ( )
4306+ . find ( |suggestion| suggestion. candidate == found) ,
42574307 _ => None ,
42584308 }
42594309 }
0 commit comments