about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2021-02-22 18:26:07 +0900
committerGitHub <noreply@github.com>2021-02-22 18:26:07 +0900
commit20c1fa17707e6cdd202a9a720f7dfe0000ecb74e (patch)
tree5788c32fcd4a3e0979bdfee4937121731566906d
parenta5f66689203cff8f96f110bf10926c2d911f6811 (diff)
parent447ce2719810f7654bb3e5a3d20fb459bb191547 (diff)
downloadrust-20c1fa17707e6cdd202a9a720f7dfe0000ecb74e.tar.gz
rust-20c1fa17707e6cdd202a9a720f7dfe0000ecb74e.zip
Rollup merge of #82287 - r00ster91:field_name_and, r=petrochenkov
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.
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs31
-rw-r--r--src/test/ui/error-codes/E0063.rs2
-rw-r--r--src/test/ui/error-codes/E0063.stderr4
-rw-r--r--src/test/ui/issues/issue-79593.rs2
-rw-r--r--src/test/ui/issues/issue-79593.stderr4
-rw-r--r--src/test/ui/parser/issue-52496.rs2
-rw-r--r--src/test/ui/parser/issue-52496.stderr4
-rw-r--r--src/test/ui/parser/struct-field-numeric-shorthand.rs2
-rw-r--r--src/test/ui/parser/struct-field-numeric-shorthand.stderr4
9 files changed, 29 insertions, 26 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 32bf0ab7e85..2faf128c491 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1348,7 +1348,6 @@ 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 =
@@ -1356,25 +1355,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         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
diff --git a/src/test/ui/error-codes/E0063.rs b/src/test/ui/error-codes/E0063.rs
index 37fc0a2987d..58527cc0c5d 100644
--- a/src/test/ui/error-codes/E0063.rs
+++ b/src/test/ui/error-codes/E0063.rs
@@ -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};
diff --git a/src/test/ui/error-codes/E0063.stderr b/src/test/ui/error-codes/E0063.stderr
index 5d366e0c1c4..5dc4927071b 100644
--- a/src/test/ui/error-codes/E0063.stderr
+++ b/src/test/ui/error-codes/E0063.stderr
@@ -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
diff --git a/src/test/ui/issues/issue-79593.rs b/src/test/ui/issues/issue-79593.rs
index fb54b36940d..b94278bfdd2 100644
--- a/src/test/ui/issues/issue-79593.rs
+++ b/src/test/ui/issues/issue-79593.rs
@@ -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() {}
diff --git a/src/test/ui/issues/issue-79593.stderr b/src/test/ui/issues/issue-79593.stderr
index 33dbd85032e..b8c7d4f23a2 100644
--- a/src/test/ui/issues/issue-79593.stderr
+++ b/src/test/ui/issues/issue-79593.stderr
@@ -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
 
diff --git a/src/test/ui/parser/issue-52496.rs b/src/test/ui/parser/issue-52496.rs
index 4e945365373..05461f8b8c4 100644
--- a/src/test/ui/parser/issue-52496.rs
+++ b/src/test/ui/parser/issue-52496.rs
@@ -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 `.`
 }
diff --git a/src/test/ui/parser/issue-52496.stderr b/src/test/ui/parser/issue-52496.stderr
index 10fcc46f344..9dbf26ef4b6 100644
--- a/src/test/ui/parser/issue-52496.stderr
+++ b/src/test/ui/parser/issue-52496.stderr
@@ -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
 
diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.rs b/src/test/ui/parser/struct-field-numeric-shorthand.rs
index 58c40b3d96a..645abd9c719 100644
--- a/src/test/ui/parser/struct-field-numeric-shorthand.rs
+++ b/src/test/ui/parser/struct-field-numeric-shorthand.rs
@@ -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`
 }
diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.stderr b/src/test/ui/parser/struct-field-numeric-shorthand.stderr
index cfb1f820147..bfb8a931b64 100644
--- a/src/test/ui/parser/struct-field-numeric-shorthand.stderr
+++ b/src/test/ui/parser/struct-field-numeric-shorthand.stderr
@@ -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