"rustc_data_structures",
"rustc_errors",
"rustc_hir",
+ "rustc_hir_pretty",
"rustc_index",
"rustc_infer",
"rustc_middle",
E0766: include_str!("./error_codes/E0766.md"),
E0767: include_str!("./error_codes/E0767.md"),
E0768: include_str!("./error_codes/E0768.md"),
+E0769: include_str!("./error_codes/E0769.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
--- /dev/null
+A tuple struct or tuple variant was used in a pattern as if it were a
+struct or struct variant.
+
+Erroneous code example:
+
+```compile_fail,E0769
+enum E {
+ A(i32),
+}
+let e = E::A(42);
+match e {
+ E::A { number } => println!("{}", x),
+}
+```
+
+To fix this error, you can use the tuple pattern:
+
+```
+# enum E {
+# A(i32),
+# }
+# let e = E::A(42);
+match e {
+ E::A(number) => println!("{}", number),
+}
+```
+
+Alternatively, you can also use the struct pattern by using the correct
+field names and binding them to new identifiers:
+
+```
+# enum E {
+# A(i32),
+# }
+# let e = E::A(42);
+match e {
+ E::A { 0: number } => println!("{}", number),
+}
+```
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
rustc_hir = { path = "../librustc_hir" }
+rustc_hir_pretty = { path = "../librustc_hir_pretty" }
rustc_target = { path = "../librustc_target" }
rustc_session = { path = "../librustc_session" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
.filter(|ident| !used_fields.contains_key(&ident))
.collect::<Vec<_>>();
- if !inexistent_fields.is_empty() && !variant.recovered {
- self.error_inexistent_fields(
+ let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered {
+ Some(self.error_inexistent_fields(
adt.variant_descr(),
&inexistent_fields,
&mut unmentioned_fields,
variant,
- );
- }
+ ))
+ } else {
+ None
+ };
// Require `..` if struct has non_exhaustive attribute.
if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
}
+ let mut unmentioned_err = None;
// Report an error if incorrect number of the fields were specified.
if adt.is_union() {
if fields.len() != 1 {
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
}
} else if !etc && !unmentioned_fields.is_empty() {
- self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant);
+ unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields));
+ }
+ match (inexistent_fields_err, unmentioned_err) {
+ (Some(mut i), Some(mut u)) => {
+ if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
+ // We don't want to show the inexistent fields error when this was
+ // `Foo { a, b }` when it should have been `Foo(a, b)`.
+ i.delay_as_bug();
+ u.delay_as_bug();
+ e.emit();
+ } else {
+ i.emit();
+ u.emit();
+ }
+ }
+ (None, Some(mut err)) | (Some(mut err), None) => {
+ err.emit();
+ }
+ (None, None) => {}
}
no_field_errors
}
inexistent_fields: &[Ident],
unmentioned_fields: &mut Vec<Ident>,
variant: &ty::VariantDef,
- ) {
+ ) -> DiagnosticBuilder<'tcx> {
let tcx = self.tcx;
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
(format!("a field named `{}`", inexistent_fields[0]), "this", "")
it explicitly.",
);
}
- err.emit();
+ err
+ }
+
+ fn error_tuple_variant_as_struct_pat(
+ &self,
+ pat: &Pat<'_>,
+ fields: &'tcx [hir::FieldPat<'tcx>],
+ variant: &ty::VariantDef,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) {
+ let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+ s.print_qpath(qpath, false)
+ });
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ pat.span,
+ E0769,
+ "tuple variant `{}` written as struct variant",
+ path
+ );
+ let (sugg, appl) = if fields.len() == variant.fields.len() {
+ (
+ fields
+ .iter()
+ .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) {
+ Ok(f) => f,
+ Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+ s.print_pat(f.pat)
+ }),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ Applicability::MachineApplicable,
+ )
+ } else {
+ (
+ variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
+ Applicability::MaybeIncorrect,
+ )
+ };
+ err.span_suggestion(
+ pat.span,
+ "use the tuple variant pattern syntax instead",
+ format!("{}({})", path, sugg),
+ appl,
+ );
+ return Some(err);
+ }
+ None
}
fn error_unmentioned_fields(
&self,
span: Span,
unmentioned_fields: &[Ident],
- variant: &ty::VariantDef,
- ) {
+ ) -> DiagnosticBuilder<'tcx> {
let field_names = if unmentioned_fields.len() == 1 {
format!("field `{}`", unmentioned_fields[0])
} else {
field_names
);
diag.span_label(span, format!("missing {}", field_names));
- if variant.ctor_kind == CtorKind::Fn {
- diag.note("trying to match a tuple variant with a struct variant pattern");
- }
if self.tcx.sess.teach(&diag.get_code().unwrap()) {
diag.note(
"This error indicates that a pattern for a struct fails to specify a \
ignore unwanted fields.",
);
}
- diag.emit();
+ diag
}
fn check_pat_box(
fn main() {
if let S { a, b, c, d } = S(1, 2, 3, 4) {
- //~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026]
- //~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027]
+ //~^ ERROR tuple variant `S` written as struct variant
println!("hi");
}
}
-error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d`
- --> $DIR/missing-fields-in-struct-pattern.rs:4:16
- |
-LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
- | ^ ^ ^ ^ struct `S` does not have these fields
-
-error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3`
+error[E0769]: tuple variant `S` written as struct variant
--> $DIR/missing-fields-in-struct-pattern.rs:4:12
|
LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
- | ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3`
- |
- = note: trying to match a tuple variant with a struct variant pattern
+ | ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
fn main() {
match X::Y(0) {
- X::Y { number } => {} //~ ERROR does not have a field named `number`
- //~^ ERROR pattern does not mention field `0`
+ X::Y { number } => {}
+ //~^ ERROR tuple variant `X::Y` written as struct variant
}
}
-error[E0026]: variant `X::Y` does not have a field named `number`
- --> $DIR/issue-41314.rs:7:16
- |
-LL | X::Y { number } => {}
- | ^^^^^^ variant `X::Y` does not have this field
-
-error[E0027]: pattern does not mention field `0`
+error[E0769]: tuple variant `X::Y` written as struct variant
--> $DIR/issue-41314.rs:7:9
|
LL | X::Y { number } => {}
- | ^^^^^^^^^^^^^^^ missing field `0`
- |
- = note: trying to match a tuple variant with a struct variant pattern
+ | ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
LL | let U { a, b } = u;
| ^^^^^^^^^^
-error[E0026]: union `U` does not have a field named `c`
- --> $DIR/union-fields-2.rs:18:19
- |
-LL | let U { a, b, c } = u;
- | ^ union `U` does not have this field
-
error: union patterns should have exactly one field
--> $DIR/union-fields-2.rs:18:9
|
LL | let U { a, b, c } = u;
| ^^^^^^^^^^^^^
+error[E0026]: union `U` does not have a field named `c`
+ --> $DIR/union-fields-2.rs:18:19
+ |
+LL | let U { a, b, c } = u;
+ | ^ union `U` does not have this field
+
error: union patterns should have exactly one field
--> $DIR/union-fields-2.rs:20:9
|