Skip to content

Commit

Permalink
limit and delimit available fields in note
Browse files Browse the repository at this point in the history
Also, don't show the note if no fields are available (usually due to
privacy).
  • Loading branch information
zackmdavis committed Aug 1, 2017
1 parent bf7e91f commit 2dbfa39
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 29 deletions.
31 changes: 22 additions & 9 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -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(..) => {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/E0559.rs
Expand Up @@ -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`
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/E0560.rs
Expand Up @@ -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`
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-19922.rs
Expand Up @@ -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`
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/numeric-fields.rs
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/struct-fields-too-many.rs
Expand Up @@ -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`
};
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/suggest-private-fields.rs
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/union/union-fields.rs
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/did_you_mean/issue-36798_unknown_field.stderr
Expand Up @@ -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

8 changes: 6 additions & 2 deletions src/test/ui/did_you_mean/issue-42599_available_fields_note.rs
Expand Up @@ -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 {
Expand All @@ -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;
}
20 changes: 10 additions & 10 deletions src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr
@@ -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

0 comments on commit 2dbfa39

Please sign in to comment.