field does not exist error: note fields if Levenshtein suggestion fails

When trying to access or initialize a nonexistent field, if we can't infer what
field was meant (by virtue of the purported field in the source being a small
Levenshtein distance away from an actual field, suggestive of a typo), issue a
note listing all the available fields. To reduce terminal clutter, we don't
issue the note when we have a `find_best_match_for_name` Levenshtein
suggestion: the suggestion is probably right.

The third argument of the call to `find_best_match_for_name` is changed to
`None`, accepting the default maximum Levenshtein distance of one-third of the
identifier supplied for correction. The previous value of `Some(name.len())`
was overzealous, inappropriately very Levenshtein-distant suggestions when the
attempted field access could not plausibly be a mere typo. For example, if a
struct has fields `mule` and `phone`, but I type `.donkey`, I'd rather the
error have a note listing that the available fields are, in fact, `mule` and
`phone` (which is the behavior induced by this patch) rather than the error
asking "did you mean `phone`?" (which is the behavior on master). The "only
find fits with at least one matching letter" comment was accurate when it was
first introduced in 09d992471 (January 2015), but is a vicious lie in its
present context before a call to `find_best_match_for_name` and must be
destroyed (replacing every letter is a Levenshtein distance of name.len()).

The present author claims that this suffices to resolve #42599.
This commit is contained in:
Zack M. Davis 2017-07-23 13:46:09 -07:00
parent 6270257f4e
commit bf7e91f61d
11 changed files with 114 additions and 13 deletions

View file

@ -15,5 +15,6 @@ enum Field {
fn main() {
let s = Field::Fool { joke: 0 };
//~^ ERROR E0559
//~| NOTE field does not exist - did you mean `x`?
//~| NOTE `Field::Fool` does not have this field
//~| NOTE available fields are: x
}

View file

@ -16,4 +16,5 @@ fn main() {
let s = Simba { mother: 1, father: 0 };
//~^ ERROR E0560
//~| NOTE `Simba` does not have this field
//~| NOTE available fields are: mother
}

View file

@ -15,5 +15,6 @@ enum Homura {
fn main() {
let homura = Homura::Akemi { kaname: () };
//~^ ERROR variant `Homura::Akemi` has no field named `kaname`
//~| NOTE field does not exist - did you mean `madoka`?
//~| NOTE `Homura::Akemi` does not have this field
//~| NOTE available fields are: madoka
}

View file

@ -13,7 +13,8 @@ struct S(u8, u16);
fn main() {
let s = S{0b1: 10, 0: 11};
//~^ ERROR struct `S` has no field named `0b1`
//~| NOTE field does not exist - did you mean `1`?
//~| NOTE `S` does not have this field
//~| NOTE available fields are: 0, 1
match s {
S{0: a, 0x1: b, ..} => {}
//~^ ERROR does not have a field named `0x1`

View file

@ -18,5 +18,6 @@ fn main() {
bar: 0
//~^ ERROR struct `BuildData` has no field named `bar`
//~| NOTE `BuildData` does not have this field
//~| NOTE available fields are: foo
};
}

View file

@ -27,7 +27,8 @@ fn main () {
//~| NOTE field does not exist - did you mean `a`?
bb: 20,
//~^ ERROR struct `xc::B` has no field named `bb`
//~| NOTE field does not exist - did you mean `a`?
//~| NOTE `xc::B` does not have this field
//~| NOTE available fields are: a
};
// local crate struct
let l = A {

View file

@ -20,6 +20,7 @@ fn main() {
let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field
//~^ ERROR union `U` has no field named `c`
//~| NOTE `U` does not have this field
//~| NOTE available fields are: a, b
let u = U { ..u }; //~ ERROR union expressions should have exactly one field
//~^ ERROR functional record update syntax requires a struct