Skip to content

Commit

Permalink
Rollup merge of rust-lang#89956 - JohnTitor:suggest-case-insensitive-…
Browse files Browse the repository at this point in the history
…match-names, r=estebank

Suggest a case insensitive match name regardless of levenshtein distance

Fixes rust-lang#86170

Currently, `find_best_match_for_name` only returns a case insensitive match name depending on a Levenshtein distance. It's a bit unfortunate that that hides some suggestions for typos like `Bar` -> `BAR`. That idea is from rust-lang#46347 (comment), but I think it still makes some sense to show a candidate when we find a case insensitive match name as it's more like a typo.
Skipped the `candidate != lookup` check because the current (i.e, `levenshtein_match`) returns the exact same `Symbol` anyway but it doesn't seem to confuse anything on UI tests.

r? `@estebank`
  • Loading branch information
matthiaskrgr committed Oct 18, 2021
2 parents 3f14625 + d4cc877 commit a284d74
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 30 deletions.
36 changes: 15 additions & 21 deletions compiler/rustc_span/src/lev_distance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,34 +58,28 @@ pub fn find_best_match_for_name(
let lookup = &lookup.as_str();
let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);

let (case_insensitive_match, levenshtein_match) = name_vec
// Priority of matches:
// 1. Exact case insensitive match
// 2. Levenshtein distance match
// 3. Sorted word match
if let Some(case_insensitive_match) =
name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase())
{
return Some(*case_insensitive_match);
}
let levenshtein_match = name_vec
.iter()
.filter_map(|&name| {
let dist = lev_distance(lookup, &name.as_str());
if dist <= max_dist { Some((name, dist)) } else { None }
})
// Here we are collecting the next structure:
// (case_insensitive_match, (levenshtein_match, levenshtein_distance))
.fold((None, None), |result, (candidate, dist)| {
(
if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
Some(candidate)
} else {
result.0
},
match result.1 {
None => Some((candidate, dist)),
Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
},
)
// (levenshtein_match, levenshtein_distance)
.fold(None, |result, (candidate, dist)| match result {
None => Some((candidate, dist)),
Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
});
// Priority of matches:
// 1. Exact case insensitive match
// 2. Levenshtein distance match
// 3. Sorted word match
if let Some(candidate) = case_insensitive_match {
Some(candidate)
} else if levenshtein_match.is_some() {
if levenshtein_match.is_some() {
levenshtein_match.map(|(candidate, _)| candidate)
} else {
find_match_by_sorted_words(name_vec, lookup)
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_span/src/lev_distance/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,12 @@ fn test_find_best_match_for_name() {

assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None);

let input = vec![Symbol::intern("aAAA")];
let input = vec![Symbol::intern("AAAA")];
assert_eq!(
find_best_match_for_name(&input, Symbol::intern("AAAA"), None),
Some(Symbol::intern("aAAA"))
find_best_match_for_name(&input, Symbol::intern("aaaa"), None),
Some(Symbol::intern("AAAA"))
);

let input = vec![Symbol::intern("AAAA")];
// Returns None because `lev_distance > max_dist / 3`
assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None);

let input = vec![Symbol::intern("AAAA")];
assert_eq!(
find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)),
Expand Down
16 changes: 15 additions & 1 deletion src/test/ui/hygiene/rustc-macro-transparency.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,43 @@ error[E0425]: cannot find value `Opaque` in this scope
--> $DIR/rustc-macro-transparency.rs:26:5
|
LL | Opaque;
| ^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `opaque`
| ^^^^^^ not found in this scope

error[E0423]: expected value, found macro `semitransparent`
--> $DIR/rustc-macro-transparency.rs:29:5
|
LL | struct SemiTransparent;
| ----------------------- similarly named unit struct `SemiTransparent` defined here
...
LL | semitransparent;
| ^^^^^^^^^^^^^^^ not a value
|
help: use `!` to invoke the macro
|
LL | semitransparent!;
| +
help: a unit struct with a similar name exists
|
LL | SemiTransparent;
| ~~~~~~~~~~~~~~~

error[E0423]: expected value, found macro `opaque`
--> $DIR/rustc-macro-transparency.rs:30:5
|
LL | struct Opaque;
| -------------- similarly named unit struct `Opaque` defined here
...
LL | opaque;
| ^^^^^^ not a value
|
help: use `!` to invoke the macro
|
LL | opaque!;
| +
help: a unit struct with a similar name exists
|
LL | Opaque;
| ~~~~~~

error: aborting due to 3 previous errors

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/issues/issue-22933-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ LL | enum Delicious {
| -------------- variant or associated item `PIE` not found here
...
LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
| ^^^ variant or associated item not found in `Delicious`
| ^^^
| |
| variant or associated item not found in `Delicious`
| help: there is a variant with a similar name: `Pie`

error: aborting due to previous error

Expand Down

0 comments on commit a284d74

Please sign in to comment.