Skip to content

Commit

Permalink
Fix span used for structured tuple struct suggestion
Browse files Browse the repository at this point in the history
(And same for tuple variants.)

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.
  • Loading branch information
camelid committed Sep 2, 2021
1 parent 50171c3 commit d2b13ba
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 10 deletions.
12 changes: 8 additions & 4 deletions compiler/rustc_typeck/src/check/expr.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -1511,7 +1515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion(
ty_span,
expr_span,
&format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
Expand All @@ -1529,7 +1533,7 @@ 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,
expr_span,
&format!(
"`{adt}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/issues/issue-4736.stderr
Expand Up @@ -5,8 +5,9 @@ LL | struct NonCopyable(());
| ----------- `NonCopyable` defined here
...
LL | let z = NonCopyable{ p: () };
| ----------- ^ field does not exist
| |
| -------------^------
| | |
| | field does not exist
| help: `NonCopyable` is a tuple struct, use the appropriate syntax: `NonCopyable(/* fields */)`

error: aborting due to previous error
Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/issues/issue-80607.stderr
Expand Up @@ -5,8 +5,9 @@ LL | V1(i32),
| -- `Enum::V1` defined here
...
LL | Enum::V1 { x }
| -------- ^ field does not exist
| |
| -----------^--
| | |
| | field does not exist
| help: `Enum::V1` is a tuple variant, use the appropriate syntax: `Enum::V1(/* fields */)`

error: aborting due to previous error
Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/numeric/numeric-fields.stderr
Expand Up @@ -5,8 +5,9 @@ LL | struct S(u8, u16);
| - `S` defined here
...
LL | let s = S{0b1: 10, 0: 11};
| - ^^^ field does not exist
| |
| --^^^------------
| | |
| | field does not exist
| help: `S` is a tuple struct, use the appropriate syntax: `S(/* fields */)`

error[E0026]: struct `S` does not have a field named `0x1`
Expand Down
18 changes: 18 additions & 0 deletions 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`
}
100 changes: 100 additions & 0 deletions src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr
@@ -0,0 +1,100 @@
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: `S(/* fields */)`

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: `S(/* fields */)`

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: `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: `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: `E::V(/* fields */)`

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: `E::V(/* fields */)`

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: `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: `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`.

0 comments on commit d2b13ba

Please sign in to comment.