@@ -120,6 +120,16 @@ struct BindingError {
120
120
target : BTreeSet < Span > ,
121
121
}
122
122
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
+
123
133
impl PartialOrd for BindingError {
124
134
fn partial_cmp ( & self , other : & BindingError ) -> Option < cmp:: Ordering > {
125
135
Some ( self . cmp ( other) )
@@ -1448,7 +1458,7 @@ impl PrimitiveTypeTable {
1448
1458
}
1449
1459
}
1450
1460
1451
- #[ derive( Default , Clone ) ]
1461
+ #[ derive( Debug , Default , Clone ) ]
1452
1462
pub struct ExternPreludeEntry < ' a > {
1453
1463
extern_crate_item : Option < & ' a NameBinding < ' a > > ,
1454
1464
pub introduced_by_item : bool ,
@@ -3277,8 +3287,19 @@ impl<'a> Resolver<'a> {
3277
3287
let mut levenshtein_worked = false ;
3278
3288
3279
3289
// 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
+
3282
3303
levenshtein_worked = true ;
3283
3304
}
3284
3305
@@ -4162,19 +4183,25 @@ impl<'a> Resolver<'a> {
4162
4183
None
4163
4184
}
4164
4185
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 ,
4172
4195
{
4173
- let add_module_candidates = |module : Module , names : & mut Vec < Name > | {
4196
+ let add_module_candidates = |module : Module , names : & mut Vec < TypoSuggestion > | {
4174
4197
for ( & ( ident, _) , resolution) in module. resolutions . borrow ( ) . iter ( ) {
4175
4198
if let Some ( binding) = resolution. borrow ( ) . binding {
4176
4199
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
+ } ) ;
4178
4205
}
4179
4206
}
4180
4207
}
@@ -4188,7 +4215,11 @@ impl<'a> Resolver<'a> {
4188
4215
// Locals and type parameters
4189
4216
for ( ident, def) in & rib. bindings {
4190
4217
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
+ } ) ;
4192
4223
}
4193
4224
}
4194
4225
// Items in scope
@@ -4201,7 +4232,13 @@ impl<'a> Resolver<'a> {
4201
4232
} else {
4202
4233
// Items from the prelude
4203
4234
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
+ } ) ) ;
4205
4242
if let Some ( prelude) = self . prelude {
4206
4243
add_module_candidates ( prelude, & mut names) ;
4207
4244
}
@@ -4213,7 +4250,13 @@ impl<'a> Resolver<'a> {
4213
4250
// Add primitive types to the mix
4214
4251
if filter_fn ( Def :: PrimTy ( Bool ) ) {
4215
4252
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
+ } )
4217
4260
)
4218
4261
}
4219
4262
} else {
@@ -4230,9 +4273,16 @@ impl<'a> Resolver<'a> {
4230
4273
4231
4274
let name = path[ path. len ( ) - 1 ] . ident . name ;
4232
4275
// 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) ,
4236
4286
_ => None ,
4237
4287
}
4238
4288
}
0 commit comments