Skip to content

Commit

Permalink
Rollup merge of #82287 - r00ster91:field_name_and, r=petrochenkov
Browse files Browse the repository at this point in the history
Make "missing field" error message more natural

```rust
struct A {
    x: i32,
    y: i32,
    z: i32,
}

fn main() {
    A { };
}
```
```
error[E0063]: missing fields `x`, `y`, `z` in initializer of `A`
 --> src/main.rs:8:5
  |
8 |     A { };
  |     ^ missing `x`, `y`, `z`
```
This error is now:
```
error[E0063]: missing fields `x`, `y` and `z` in initializer of `A`
 --> src/main.rs:8:5
  |
8 |     A { };
  |     ^ missing `x`, `y` and `z`
```
I thought it looked nicer and more natural this way. Also, if there is >3 fields missing, there is an "and" as well ("missing \`x\`, \`y\`, \`z\` *and* 1 other field"), but for <=3 there is not. As such it improves consistency too.

As for the implementation, originally I ended up with a chunky `push_str` algorithm but then I figured I could just do the formatting manually since it's just 3 field names at maximum. It is comparatively readable.

As a sidenote, one thing I was wondering about is, isn't there more cases where you have a list of things like field names? Maybe this whole thing can at some point later be made into a more general function to be used in multiple areas.
  • Loading branch information
JohnTitor authored Feb 22, 2021
2 parents a5f6668 + 447ce27 commit 20c1fa1
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 26 deletions.
31 changes: 17 additions & 14 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1348,33 +1348,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
) {
let tcx = self.tcx;
let len = remaining_fields.len();

let mut displayable_field_names =
remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();

displayable_field_names.sort();

let truncated_fields_error = if len <= 3 {
String::new()
} else {
format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
let mut truncated_fields_error = String::new();
let remaining_fields_names = match &displayable_field_names[..] {
[field1] => format!("`{}`", field1),
[field1, field2] => format!("`{}` and `{}`", field1, field2),
[field1, field2, field3] => format!("`{}`, `{}` and `{}`", field1, field2, field3),
_ => {
truncated_fields_error =
format!(" and {} other field{}", len - 3, pluralize!(len - 3));
displayable_field_names
.iter()
.take(3)
.map(|n| format!("`{}`", n))
.collect::<Vec<_>>()
.join(", ")
}
};

let remaining_fields_names = displayable_field_names
.iter()
.take(3)
.map(|n| format!("`{}`", n))
.collect::<Vec<_>>()
.join(", ");

struct_span_err!(
tcx.sess,
self.tcx.sess,
span,
E0063,
"missing field{} {}{} in initializer of `{}`",
pluralize!(remaining_fields.len()),
pluralize!(len),
remaining_fields_names,
truncated_fields_error,
adt_ty
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0063.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() {
let w = SingleFoo { };
//~^ ERROR missing field `x` in initializer of `SingleFoo`
let x = PluralFoo {x: 1};
//~^ ERROR missing fields `y`, `z` in initializer of `PluralFoo`
//~^ ERROR missing fields `y` and `z` in initializer of `PluralFoo`
let y = TruncatedFoo{x:1};
//~^ missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo`
let z = TruncatedPluralFoo{x:1};
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0063.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0063]: missing field `x` in initializer of `SingleFoo`
LL | let w = SingleFoo { };
| ^^^^^^^^^ missing `x`

error[E0063]: missing fields `y`, `z` in initializer of `PluralFoo`
error[E0063]: missing fields `y` and `z` in initializer of `PluralFoo`
--> $DIR/E0063.rs:34:13
|
LL | let x = PluralFoo {x: 1};
| ^^^^^^^^^ missing `y`, `z`
| ^^^^^^^^^ missing `y` and `z`

error[E0063]: missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo`
--> $DIR/E0063.rs:36:13
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-79593.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn wrong() {
foo::Enum::Variant { x: () };
//~^ ERROR missing field `y` in initializer of `Enum`
foo::Enum::Variant { };
//~^ ERROR missing fields `x`, `y` in initializer of `Enum`
//~^ ERROR missing fields `x` and `y` in initializer of `Enum`
}

fn main() {}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-79593.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ error[E0063]: missing field `y` in initializer of `Enum`
LL | foo::Enum::Variant { x: () };
| ^^^^^^^^^^^^^^^^^^ missing `y`

error[E0063]: missing fields `x`, `y` in initializer of `Enum`
error[E0063]: missing fields `x` and `y` in initializer of `Enum`
--> $DIR/issue-79593.rs:25:5
|
LL | foo::Enum::Variant { };
| ^^^^^^^^^^^^^^^^^^ missing `x`, `y`
| ^^^^^^^^^^^^^^^^^^ missing `x` and `y`

error: aborting due to 5 previous errors

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/parser/issue-52496.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ fn main() {
let bar = 1.5f32;
let _ = Foo { bar.into(), bat: -1, . };
//~^ ERROR expected one of
//~| ERROR missing fields `bar`, `baz` in initializer of `Foo`
//~| ERROR missing fields `bar` and `baz` in initializer of `Foo`
//~| ERROR expected identifier, found `.`
}
4 changes: 2 additions & 2 deletions src/test/ui/parser/issue-52496.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ error[E0063]: missing field `bat` in initializer of `Foo`
LL | let _ = Foo { bar: .5, baz: 42 };
| ^^^ missing `bat`

error[E0063]: missing fields `bar`, `baz` in initializer of `Foo`
error[E0063]: missing fields `bar` and `baz` in initializer of `Foo`
--> $DIR/issue-52496.rs:8:13
|
LL | let _ = Foo { bar.into(), bat: -1, . };
| ^^^ missing `bar`, `baz`
| ^^^ missing `bar` and `baz`

error: aborting due to 5 previous errors

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/parser/struct-field-numeric-shorthand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ fn main() {
//~^ ERROR expected identifier, found `0`
//~| ERROR expected identifier, found `1`
//~| ERROR expected identifier, found `2`
//~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
//~| ERROR missing fields `0`, `1` and `2` in initializer of `Rgb`
}
4 changes: 2 additions & 2 deletions src/test/ui/parser/struct-field-numeric-shorthand.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ LL | let _ = Rgb { 0, 1, 2 };
| |
| while parsing this struct

error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
error[E0063]: missing fields `0`, `1` and `2` in initializer of `Rgb`
--> $DIR/struct-field-numeric-shorthand.rs:4:13
|
LL | let _ = Rgb { 0, 1, 2 };
| ^^^ missing `0`, `1`, `2`
| ^^^ missing `0`, `1` and `2`

error: aborting due to 4 previous errors

Expand Down

0 comments on commit 20c1fa1

Please sign in to comment.