]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #82287 - r00ster91:field_name_and, r=petrochenkov
authorYuki Okushi <huyuumi.dev@gmail.com>
Mon, 22 Feb 2021 09:26:07 +0000 (18:26 +0900)
committerGitHub <noreply@github.com>
Mon, 22 Feb 2021 09:26:07 +0000 (18:26 +0900)
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.

1  2 
compiler/rustc_typeck/src/check/expr.rs

index 32bf0ab7e85331fe01ff02aaae4ef841cefa5ada,58cab950b2892566e3185784b48d3f652b0c9bd6..2faf128c491fdc3af54b65096853fecfa0520b6f
@@@ -1348,7 -1348,6 +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 =
  
          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
              }
              _ => {
                  self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
 +                // Avoid expressions without types during writeback (#78653).
 +                self.check_expr(value);
                  self.tcx.mk_unit()
              }
          }