limit and delimit available fields in note

Also, don't show the note if no fields are available (usually due to
privacy).
This commit is contained in:
Zack M. Davis 2017-07-31 00:31:32 -07:00
parent bf7e91f61d
commit 2dbfa3995e
11 changed files with 46 additions and 29 deletions

View file

@ -2957,10 +2957,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} else {
err.span_label(field.span, "unknown field");
let struct_variant_def = def.struct_variant();
let available_field_names = self.available_field_names(
struct_variant_def);
err.note(&format!("available fields are: {}",
available_field_names.join(", ")));
let field_names = self.available_field_names(struct_variant_def);
if !field_names.is_empty() {
err.note(&format!("available fields are: {}",
self.name_series_display(field_names)));
}
};
}
ty::TyRawPtr(..) => {
@ -3000,17 +3001,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
find_best_match_for_name(names, &name, None)
}
fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<String> {
fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<ast::Name> {
let mut available = Vec::new();
for field in variant.fields.iter() {
let (_, def_scope) = self.tcx.adjust(field.name, variant.did, self.body_id);
if field.vis.is_accessible_from(def_scope, self.tcx) {
available.push(field.name.to_string());
available.push(field.name);
}
}
available
}
fn name_series_display(&self, names: Vec<ast::Name>) -> String {
// dynamic limit, to never omit just one field
let limit = if names.len() == 6 { 6 } else { 5 };
let mut display = names.iter().take(limit)
.map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
if names.len() > limit {
display = format!("{} ... and {} others", display, names.len() - limit);
}
display
}
// Check tuple index expressions
fn check_tup_field(&self,
expr: &'gcx hir::Expr,
@ -3132,12 +3144,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
format!("`{}` does not have this field", ty));
}
let available_field_names = self.available_field_names(variant);
err.note(&format!("available fields are: {}",
available_field_names.join(", ")));
if !available_field_names.is_empty() {
err.note(&format!("available fields are: {}",
self.name_series_display(available_field_names)));
}
}
_ => bug!("non-ADT passed to report_unknown_field")
}
};
err.emit();
}

View file

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

View file

@ -16,5 +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
//~| NOTE available fields are: `mother`
}

View file

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

View file

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

View file

@ -18,6 +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
//~| NOTE available fields are: `foo`
};
}

View file

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

View file

@ -20,7 +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
//~| 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

View file

@ -4,7 +4,7 @@ error[E0609]: no field `zz` on type `Foo`
17 | f.zz;
| ^^ unknown field
|
= note: available fields are: bar
= note: available fields are: `bar`
error: aborting due to previous error

View file

@ -14,7 +14,11 @@ mod submodule {
pub struct Demo {
pub favorite_integer: isize,
secret_integer: isize,
pub innocently_misspellable: ()
pub innocently_misspellable: (),
another_field: bool,
yet_another_field: bool,
always_more_fields: bool,
and_ever: bool,
}
impl Demo {
@ -34,6 +38,6 @@ fn main() {
let demo = Demo::default();
let innocent_field_misaccess = demo.inocently_mispellable;
// note shouldn't suggest private `secret_integer` field
// note shouldn't suggest private fields
let egregious_field_misaccess = demo.egregiously_nonexistent_field;
}

View file

@ -1,30 +1,30 @@
error[E0560]: struct `submodule::Demo` has no field named `inocently_mispellable`
--> $DIR/issue-42599_available_fields_note.rs:22:39
--> $DIR/issue-42599_available_fields_note.rs:26:39
|
22 | Self { secret_integer: 2, inocently_mispellable: () }
26 | Self { secret_integer: 2, inocently_mispellable: () }
| ^^^^^^^^^^^^^^^^^^^^^^ field does not exist - did you mean `innocently_misspellable`?
error[E0560]: struct `submodule::Demo` has no field named `egregiously_nonexistent_field`
--> $DIR/issue-42599_available_fields_note.rs:26:39
--> $DIR/issue-42599_available_fields_note.rs:30:39
|
26 | Self { secret_integer: 3, egregiously_nonexistent_field: () }
30 | Self { secret_integer: 3, egregiously_nonexistent_field: () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field
|
= note: available fields are: favorite_integer, secret_integer, innocently_misspellable
= note: available fields are: `favorite_integer`, `secret_integer`, `innocently_misspellable`, `another_field`, `yet_another_field` ... and 2 others
error[E0609]: no field `inocently_mispellable` on type `submodule::Demo`
--> $DIR/issue-42599_available_fields_note.rs:36:41
--> $DIR/issue-42599_available_fields_note.rs:40:41
|
36 | let innocent_field_misaccess = demo.inocently_mispellable;
40 | let innocent_field_misaccess = demo.inocently_mispellable;
| ^^^^^^^^^^^^^^^^^^^^^ did you mean `innocently_misspellable`?
error[E0609]: no field `egregiously_nonexistent_field` on type `submodule::Demo`
--> $DIR/issue-42599_available_fields_note.rs:38:42
--> $DIR/issue-42599_available_fields_note.rs:42:42
|
38 | let egregious_field_misaccess = demo.egregiously_nonexistent_field;
42 | let egregious_field_misaccess = demo.egregiously_nonexistent_field;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown field
|
= note: available fields are: favorite_integer, innocently_misspellable
= note: available fields are: `favorite_integer`, `innocently_misspellable`
error: aborting due to 4 previous errors