@@ -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 ,
@@ -3277,8 +3287,19 @@ impl<'a> Resolver<'a> {
32773287 let mut levenshtein_worked = false ;
32783288
32793289 // Try Levenshtein algorithm.
3280- if let Some ( candidate) = this. lookup_typo_candidate ( path, ns, is_expected, span) {
3281- err. span_label ( ident_span, format ! ( "did you mean `{}`?" , candidate) ) ;
3290+ let suggestion = this. lookup_typo_candidate ( path, ns, is_expected, span) ;
3291+ if let Some ( suggestion) = suggestion {
3292+ let msg = format ! (
3293+ "{} {} with a similar name exists" ,
3294+ suggestion. article, suggestion. kind
3295+ ) ;
3296+ err. span_suggestion_with_applicability (
3297+ ident_span,
3298+ & msg,
3299+ suggestion. candidate . to_string ( ) ,
3300+ Applicability :: MaybeIncorrect ,
3301+ ) ;
3302+
32823303 levenshtein_worked = true ;
32833304 }
32843305
@@ -4162,19 +4183,25 @@ impl<'a> Resolver<'a> {
41624183 None
41634184 }
41644185
4165- fn lookup_typo_candidate < FilterFn > ( & mut self ,
4166- path : & [ Segment ] ,
4167- ns : Namespace ,
4168- filter_fn : FilterFn ,
4169- span : Span )
4170- -> Option < Symbol >
4171- where FilterFn : Fn ( Def ) -> bool
4186+ fn lookup_typo_candidate < FilterFn > (
4187+ & mut self ,
4188+ path : & [ Segment ] ,
4189+ ns : Namespace ,
4190+ filter_fn : FilterFn ,
4191+ span : Span ,
4192+ ) -> Option < TypoSuggestion >
4193+ where
4194+ FilterFn : Fn ( Def ) -> bool ,
41724195 {
4173- let add_module_candidates = |module : Module , names : & mut Vec < Name > | {
4196+ let add_module_candidates = |module : Module , names : & mut Vec < TypoSuggestion > | {
41744197 for ( & ( ident, _) , resolution) in module. resolutions . borrow ( ) . iter ( ) {
41754198 if let Some ( binding) = resolution. borrow ( ) . binding {
41764199 if filter_fn ( binding. def ( ) ) {
4177- names. push ( ident. name ) ;
4200+ names. push ( TypoSuggestion {
4201+ candidate : ident. name ,
4202+ article : binding. def ( ) . article ( ) ,
4203+ kind : binding. def ( ) . kind_name ( ) ,
4204+ } ) ;
41784205 }
41794206 }
41804207 }
@@ -4188,7 +4215,11 @@ impl<'a> Resolver<'a> {
41884215 // Locals and type parameters
41894216 for ( ident, def) in & rib. bindings {
41904217 if filter_fn ( * def) {
4191- names. push ( ident. name ) ;
4218+ names. push ( TypoSuggestion {
4219+ candidate : ident. name ,
4220+ article : def. article ( ) ,
4221+ kind : def. kind_name ( ) ,
4222+ } ) ;
41924223 }
41934224 }
41944225 // Items in scope
@@ -4201,7 +4232,13 @@ impl<'a> Resolver<'a> {
42014232 } else {
42024233 // Items from the prelude
42034234 if !module. no_implicit_prelude {
4204- names. extend ( self . extern_prelude . iter ( ) . map ( |( ident, _) | ident. name ) ) ;
4235+ names. extend ( self . extern_prelude . iter ( ) . map ( |( ident, _) | {
4236+ TypoSuggestion {
4237+ candidate : ident. name ,
4238+ article : "a" ,
4239+ kind : "crate" ,
4240+ }
4241+ } ) ) ;
42054242 if let Some ( prelude) = self . prelude {
42064243 add_module_candidates ( prelude, & mut names) ;
42074244 }
@@ -4213,7 +4250,13 @@ impl<'a> Resolver<'a> {
42134250 // Add primitive types to the mix
42144251 if filter_fn ( Def :: PrimTy ( Bool ) ) {
42154252 names. extend (
4216- self . primitive_type_table . primitive_types . iter ( ) . map ( |( name, _) | name)
4253+ self . primitive_type_table . primitive_types . iter ( ) . map ( |( name, _) | {
4254+ TypoSuggestion {
4255+ candidate : * name,
4256+ article : "a" ,
4257+ kind : "primitive type" ,
4258+ }
4259+ } )
42174260 )
42184261 }
42194262 } else {
@@ -4230,9 +4273,16 @@ impl<'a> Resolver<'a> {
42304273
42314274 let name = path[ path. len ( ) - 1 ] . ident . name ;
42324275 // Make sure error reporting is deterministic.
4233- names. sort_by_cached_key ( |name| name. as_str ( ) ) ;
4234- match find_best_match_for_name ( names. iter ( ) , & name. as_str ( ) , None ) {
4235- Some ( found) if found != name => Some ( found) ,
4276+ names. sort_by_cached_key ( |suggestion| suggestion. candidate . as_str ( ) ) ;
4277+
4278+ match find_best_match_for_name (
4279+ names. iter ( ) . map ( |suggestion| & suggestion. candidate ) ,
4280+ & name. as_str ( ) ,
4281+ None ,
4282+ ) {
4283+ Some ( found) if found != name => names
4284+ . into_iter ( )
4285+ . find ( |suggestion| suggestion. candidate == found) ,
42364286 _ => None ,
42374287 }
42384288 }
0 commit comments