about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-09-06 07:58:24 +0000
committerbors <bors@rust-lang.org>2021-09-06 07:58:24 +0000
commitd19d864e79531ad702e4f44b2635da6c50cc5eb0 (patch)
tree2b750bf335f2e0d0c4856020bce6ceae1cfa2c1f
parentb2d9bcda7ec267dbabfaef67f7af344ef71e002c (diff)
parent2226977a875c149effeb7d6b85bce5a5ba0c440c (diff)
downloadrust-d19d864e79531ad702e4f44b2635da6c50cc5eb0.tar.gz
rust-d19d864e79531ad702e4f44b2635da6c50cc5eb0.zip
Auto merge of #88631 - camelid:sugg-span, r=davidtwco
Improve structured tuple struct suggestion

Previously, the span was just for the constructor name, which meant it
would result in syntactically-invalid code when applied. Now, the span
is for the entire expression.

I also changed it to use `span_suggestion_verbose`, for two reasons:

1. Now that the suggestion span has been corrected, the output is a bit
   cluttered and hard to read. Putting the suggestion its own window
   creates more space.

2. It's easier to see what's being suggested, since now the version
   after the suggestion is applied is shown.

r? `@davidtwco`
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs16
-rw-r--r--src/test/ui/issues/issue-4736.stderr9
-rw-r--r--src/test/ui/issues/issue-80607.stderr9
-rw-r--r--src/test/ui/numeric/numeric-fields.stderr9
-rw-r--r--src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs18
-rw-r--r--src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr116
6 files changed, 162 insertions, 15 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 64594a82ec0..d578fac4cdb 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1236,6 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             variant,
             fields,
             base_expr.is_none(),
+            expr.span,
         );
         if let Some(base_expr) = base_expr {
             // If check_expr_struct_fields hit an error, do not attempt to populate
@@ -1283,6 +1284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         variant: &'tcx ty::VariantDef,
         ast_fields: &'tcx [hir::ExprField<'tcx>],
         check_completeness: bool,
+        expr_span: Span,
     ) -> bool {
         let tcx = self.tcx;
 
@@ -1334,7 +1336,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ident,
                     });
                 } else {
-                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span);
+                    self.report_unknown_field(
+                        adt_ty, variant, field, ast_fields, kind_name, expr_span,
+                    );
                 }
 
                 tcx.ty_error()
@@ -1467,7 +1471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         field: &hir::ExprField<'_>,
         skip_fields: &[hir::ExprField<'_>],
         kind_name: &str,
-        ty_span: Span,
+        expr_span: Span,
     ) {
         if variant.is_recovered() {
             self.set_tainted_by_errors();
@@ -1510,8 +1514,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ),
                     );
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_suggestion(
-                        ty_span,
+                    err.span_suggestion_verbose(
+                        expr_span,
                         &format!(
                             "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
@@ -1528,8 +1532,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => {
                     err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_suggestion(
-                        ty_span,
+                    err.span_suggestion_verbose(
+                        expr_span,
                         &format!(
                             "`{adt}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
diff --git a/src/test/ui/issues/issue-4736.stderr b/src/test/ui/issues/issue-4736.stderr
index 9be4eb1c7fd..2a1f1819c33 100644
--- a/src/test/ui/issues/issue-4736.stderr
+++ b/src/test/ui/issues/issue-4736.stderr
@@ -5,9 +5,12 @@ LL | struct NonCopyable(());
    |        ----------- `NonCopyable` defined here
 ...
 LL |     let z = NonCopyable{ p: () };
-   |             -----------  ^ field does not exist
-   |             |
-   |             help: `NonCopyable` is a tuple struct, use the appropriate syntax: `NonCopyable(/* fields */)`
+   |                          ^ field does not exist
+   |
+help: `NonCopyable` is a tuple struct, use the appropriate syntax
+   |
+LL |     let z = NonCopyable(/* fields */);
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-80607.stderr b/src/test/ui/issues/issue-80607.stderr
index 22a660b4167..38e46683b08 100644
--- a/src/test/ui/issues/issue-80607.stderr
+++ b/src/test/ui/issues/issue-80607.stderr
@@ -5,9 +5,12 @@ LL |     V1(i32),
    |     -- `Enum::V1` defined here
 ...
 LL |     Enum::V1 { x }
-   |     --------   ^ field does not exist
-   |     |
-   |     help: `Enum::V1` is a tuple variant, use the appropriate syntax: `Enum::V1(/* fields */)`
+   |                ^ field does not exist
+   |
+help: `Enum::V1` is a tuple variant, use the appropriate syntax
+   |
+LL |     Enum::V1(/* fields */)
+   |     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/numeric/numeric-fields.stderr b/src/test/ui/numeric/numeric-fields.stderr
index 13b6cfae4ec..b328fbe2cfb 100644
--- a/src/test/ui/numeric/numeric-fields.stderr
+++ b/src/test/ui/numeric/numeric-fields.stderr
@@ -5,9 +5,12 @@ LL | struct S(u8, u16);
    |        - `S` defined here
 ...
 LL |     let s = S{0b1: 10, 0: 11};
-   |             - ^^^ field does not exist
-   |             |
-   |             help: `S` is a tuple struct, use the appropriate syntax: `S(/* fields */)`
+   |               ^^^ field does not exist
+   |
+help: `S` is a tuple struct, use the appropriate syntax
+   |
+LL |     let s = S(/* fields */);
+   |             ~~~~~~~~~~~~~~~
 
 error[E0026]: struct `S` does not have a field named `0x1`
   --> $DIR/numeric-fields.rs:7:17
diff --git a/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs b/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs
new file mode 100644
index 00000000000..308adcf01fe
--- /dev/null
+++ b/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs
@@ -0,0 +1,18 @@
+pub struct S(f32, f32);
+
+pub enum E {
+    V(f32, f32),
+}
+
+fn main() {
+    let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 });
+    //~^ ERROR struct `S` has no field named `x`
+    //~| ERROR struct `S` has no field named `y`
+    //~| ERROR struct `S` has no field named `x`
+    //~| ERROR struct `S` has no field named `y`
+    let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 });
+    //~^ ERROR variant `E::V` has no field named `x`
+    //~| ERROR variant `E::V` has no field named `y`
+    //~| ERROR variant `E::V` has no field named `x`
+    //~| ERROR variant `E::V` has no field named `y`
+}
diff --git a/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr b/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr
new file mode 100644
index 00000000000..948f09fc3fa
--- /dev/null
+++ b/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr
@@ -0,0 +1,116 @@
+error[E0560]: struct `S` has no field named `x`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:8:19
+   |
+LL | pub struct S(f32, f32);
+   |            - `S` defined here
+...
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 });
+   |                   ^ field does not exist
+   |
+help: `S` is a tuple struct, use the appropriate syntax
+   |
+LL |     let _x = (S(/* fields */), S { x: 3.0, y: 4.0 });
+   |               ~~~~~~~~~~~~~~~
+
+error[E0560]: struct `S` has no field named `y`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:8:27
+   |
+LL | pub struct S(f32, f32);
+   |            - `S` defined here
+...
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 });
+   |                           ^ field does not exist
+   |
+help: `S` is a tuple struct, use the appropriate syntax
+   |
+LL |     let _x = (S(/* fields */), S { x: 3.0, y: 4.0 });
+   |               ~~~~~~~~~~~~~~~
+
+error[E0560]: struct `S` has no field named `x`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:8:41
+   |
+LL | pub struct S(f32, f32);
+   |            - `S` defined here
+...
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 });
+   |                                         ^ field does not exist
+   |
+help: `S` is a tuple struct, use the appropriate syntax
+   |
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */));
+   |                                     ~~~~~~~~~~~~~~~
+
+error[E0560]: struct `S` has no field named `y`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:8:49
+   |
+LL | pub struct S(f32, f32);
+   |            - `S` defined here
+...
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 });
+   |                                                 ^ field does not exist
+   |
+help: `S` is a tuple struct, use the appropriate syntax
+   |
+LL |     let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */));
+   |                                     ~~~~~~~~~~~~~~~
+
+error[E0559]: variant `E::V` has no field named `x`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:13:22
+   |
+LL |     V(f32, f32),
+   |     - `E::V` defined here
+...
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 });
+   |                      ^ field does not exist
+   |
+help: `E::V` is a tuple variant, use the appropriate syntax
+   |
+LL |     let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 });
+   |               ~~~~~~~~~~~~~~~~~~
+
+error[E0559]: variant `E::V` has no field named `y`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:13:30
+   |
+LL |     V(f32, f32),
+   |     - `E::V` defined here
+...
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 });
+   |                              ^ field does not exist
+   |
+help: `E::V` is a tuple variant, use the appropriate syntax
+   |
+LL |     let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 });
+   |               ~~~~~~~~~~~~~~~~~~
+
+error[E0559]: variant `E::V` has no field named `x`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:13:47
+   |
+LL |     V(f32, f32),
+   |     - `E::V` defined here
+...
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 });
+   |                                               ^ field does not exist
+   |
+help: `E::V` is a tuple variant, use the appropriate syntax
+   |
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */));
+   |                                        ~~~~~~~~~~~~~~~~~~
+
+error[E0559]: variant `E::V` has no field named `y`
+  --> $DIR/nested-non-tuple-tuple-struct.rs:13:55
+   |
+LL |     V(f32, f32),
+   |     - `E::V` defined here
+...
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 });
+   |                                                       ^ field does not exist
+   |
+help: `E::V` is a tuple variant, use the appropriate syntax
+   |
+LL |     let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */));
+   |                                        ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0559, E0560.
+For more information about an error, try `rustc --explain E0559`.