From 2dbfa3995e44af6ce4fbeaa2f9de4730e5d2fbd5 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Mon, 31 Jul 2017 00:31:32 -0700 Subject: [PATCH] limit and delimit available fields in note Also, don't show the note if no fields are available (usually due to privacy). --- src/librustc_typeck/check/mod.rs | 31 +++++++++++++------ src/test/compile-fail/E0559.rs | 2 +- src/test/compile-fail/E0560.rs | 2 +- src/test/compile-fail/issue-19922.rs | 2 +- src/test/compile-fail/numeric-fields.rs | 2 +- .../compile-fail/struct-fields-too-many.rs | 2 +- .../compile-fail/suggest-private-fields.rs | 2 +- src/test/compile-fail/union/union-fields.rs | 2 +- .../issue-36798_unknown_field.stderr | 2 +- .../issue-42599_available_fields_note.rs | 8 +++-- .../issue-42599_available_fields_note.stderr | 20 ++++++------ 11 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4b40a46f74eef..178331afabe17 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 { + fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { 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) -> 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::>().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(); } diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs index 21bb2dc7002ca..e8b0915d2b533 100644 --- a/src/test/compile-fail/E0559.rs +++ b/src/test/compile-fail/E0559.rs @@ -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` } diff --git a/src/test/compile-fail/E0560.rs b/src/test/compile-fail/E0560.rs index 7aa6b2e86d698..955ef7ca99ceb 100644 --- a/src/test/compile-fail/E0560.rs +++ b/src/test/compile-fail/E0560.rs @@ -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` } diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs index 429c4384117a9..938ccb343d427 100644 --- a/src/test/compile-fail/issue-19922.rs +++ b/src/test/compile-fail/issue-19922.rs @@ -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` } diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs index 242c3a3a33d25..d6e091a1472cd 100644 --- a/src/test/compile-fail/numeric-fields.rs +++ b/src/test/compile-fail/numeric-fields.rs @@ -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` diff --git a/src/test/compile-fail/struct-fields-too-many.rs b/src/test/compile-fail/struct-fields-too-many.rs index 78ab94d5fb4d9..b1af142ad0fd2 100644 --- a/src/test/compile-fail/struct-fields-too-many.rs +++ b/src/test/compile-fail/struct-fields-too-many.rs @@ -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` }; } diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs index 959932af9b1d7..d0752b5f02f06 100644 --- a/src/test/compile-fail/suggest-private-fields.rs +++ b/src/test/compile-fail/suggest-private-fields.rs @@ -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 { diff --git a/src/test/compile-fail/union/union-fields.rs b/src/test/compile-fail/union/union-fields.rs index 2bcc2204e3345..124b16f99b1af 100644 --- a/src/test/compile-fail/union/union-fields.rs +++ b/src/test/compile-fail/union/union-fields.rs @@ -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 diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr index 610466c894aa7..20bb7d4c91de3 100644 --- a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -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 diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.rs b/src/test/ui/did_you_mean/issue-42599_available_fields_note.rs index 4b0cc7b96a765..7fe9950801227 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.rs +++ b/src/test/ui/did_you_mean/issue-42599_available_fields_note.rs @@ -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; } diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr index 17edac92fd9d9..e2bb7fbd9a895 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/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