Skip to content

Commit dcc59c0

Browse files
committed
Auto merge of #26087 - fitzgen:improve-suggestion-hueristics, r=Aatch
This makes the maximum edit distance of typo suggestions a function of the typo'd name's length. FWIW, clang uses this same hueristic, and I've found their suggestions to be better than rustc's. Without something like this, you end up with suggestions that aren't related at all when there are short variable names. See also #20028 (comment)
2 parents 8f9f2fe + 93d01eb commit dcc59c0

File tree

4 files changed

+35
-14
lines changed

4 files changed

+35
-14
lines changed

src/librustc_resolve/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,14 +3206,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
32063206
NoSuggestion
32073207
}
32083208

3209-
fn find_best_match_for_name(&mut self, name: &str, max_distance: usize)
3210-
-> Option<String> {
3211-
let this = &mut *self;
3212-
3209+
fn find_best_match_for_name(&mut self, name: &str) -> Option<String> {
32133210
let mut maybes: Vec<token::InternedString> = Vec::new();
32143211
let mut values: Vec<usize> = Vec::new();
32153212

3216-
for rib in this.value_ribs.iter().rev() {
3213+
for rib in self.value_ribs.iter().rev() {
32173214
for (&k, _) in &rib.bindings {
32183215
maybes.push(token::get_name(k));
32193216
values.push(usize::MAX);
@@ -3229,9 +3226,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
32293226
}
32303227
}
32313228

3229+
// As a loose rule to avoid obviously incorrect suggestions, clamp the
3230+
// maximum edit distance we will accept for a suggestion to one third of
3231+
// the typo'd name's length.
3232+
let max_distance = std::cmp::max(name.len(), 3) / 3;
3233+
32323234
if !values.is_empty() &&
3233-
values[smallest] != usize::MAX &&
3234-
values[smallest] < name.len() + 2 &&
32353235
values[smallest] <= max_distance &&
32363236
name != &maybes[smallest][..] {
32373237

@@ -3357,7 +3357,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
33573357
NoSuggestion => {
33583358
// limit search to 5 to reduce the number
33593359
// of stupid suggestions
3360-
self.find_best_match_for_name(&path_name, 5)
3360+
self.find_best_match_for_name(&path_name)
33613361
.map_or("".to_string(),
33623362
|x| format!("`{}`", x))
33633363
}

src/test/compile-fail/bad-expr-path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern: unresolved name `m1::a`. Did you mean `args`?
11+
// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
1212

1313
mod m1 {}
1414

15-
fn main(args: Vec<String>) { log(debug, m1::a); }
15+
fn main(arguments: Vec<String>) { log(debug, m1::arguments); }

src/test/compile-fail/bad-expr-path2.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern: unresolved name `m1::a`. Did you mean `args`?
11+
// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
1212

1313
mod m1 {
14-
pub mod a {}
14+
pub mod arguments {}
1515
}
1616

17-
fn main(args: Vec<String>) {
18-
log(debug, m1::a);
17+
fn main(arguments: Vec<String>) {
18+
log(debug, m1::arguments);
1919
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let foo = 1;
13+
14+
// `foo` shouldn't be suggested, it is too dissimilar from `bar`.
15+
println!("Hello {}", bar);
16+
//~^ ERROR: unresolved name `bar`
17+
18+
// But this is close enough.
19+
println!("Hello {}", fob);
20+
//~^ ERROR: unresolved name `fob`. Did you mean `foo`?
21+
}

0 commit comments

Comments
 (0)