about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs57
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr18
-rw-r--r--src/test/ui/error-codes/E0023.stderr9
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr9
-rw-r--r--src/test/ui/issues/issue-72574-2.stderr5
-rw-r--r--src/test/ui/match/match-pattern-field-mismatch.stderr9
-rw-r--r--src/test/ui/pattern/issue-74539.stderr5
-rw-r--r--src/test/ui/pattern/pat-tuple-underfield.rs55
-rw-r--r--src/test/ui/pattern/pat-tuple-underfield.stderr131
9 files changed, 291 insertions, 7 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 5fc573a57ad..ecc6e8599ad 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -15,6 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 
 use std::cmp;
@@ -1001,7 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // More generally, the expected type wants a tuple variant with one field of an
         // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
         // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
-        let missing_parenthesis = match (&expected.kind(), fields, had_err) {
+        let missing_parentheses = match (&expected.kind(), fields, had_err) {
             // #67037: only do this if we could successfully type-check the expected type against
             // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
             // `let P() = U;` where `P != U` with `struct P<T>(T);`.
@@ -1014,13 +1015,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => false,
         };
-        if missing_parenthesis {
+        if missing_parentheses {
             let (left, right) = match subpats {
                 // This is the zero case; we aim to get the "hi" part of the `QPath`'s
                 // span as the "lo" and then the "hi" part of the pattern's span as the "hi".
                 // This looks like:
                 //
-                // help: missing parenthesis
+                // help: missing parentheses
                 //   |
                 // L |     let A(()) = A(());
                 //   |          ^  ^
@@ -1029,17 +1030,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // last sub-pattern. In the case of `A(x)` the first and last may coincide.
                 // This looks like:
                 //
-                // help: missing parenthesis
+                // help: missing parentheses
                 //   |
                 // L |     let A((x, y)) = A((1, 2));
                 //   |           ^    ^
                 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
             };
             err.multipart_suggestion(
-                "missing parenthesis",
+                "missing parentheses",
                 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
                 Applicability::MachineApplicable,
             );
+        } else if fields.len() > subpats.len() {
+            let after_fields_span = if pat_span == DUMMY_SP {
+                pat_span
+            } else {
+                pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi()
+            };
+            let all_fields_span = match subpats {
+                [] => after_fields_span,
+                [field] => field.span,
+                [first, .., last] => first.span.to(last.span),
+            };
+
+            // Check if all the fields in the pattern are wildcards.
+            let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
+
+            let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
+            if !subpats.is_empty() {
+                wildcard_sugg = String::from(", ") + &wildcard_sugg;
+            }
+
+            err.span_suggestion_verbose(
+                after_fields_span,
+                "use `_` to explicitly ignore each field",
+                wildcard_sugg,
+                Applicability::MaybeIncorrect,
+            );
+
+            // Only suggest `..` if more than one field is missing
+            // or the pattern consists of all wildcards.
+            if fields.len() - subpats.len() > 1 || all_wildcards {
+                if subpats.is_empty() || all_wildcards {
+                    err.span_suggestion_verbose(
+                        all_fields_span,
+                        "use `..` to ignore all fields",
+                        String::from(".."),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        after_fields_span,
+                        "use `..` to ignore the rest of the fields",
+                        String::from(", .."),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
         }
 
         err.emit();
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
index 0e7174e5b19..c270593cac7 100644
--- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
@@ -31,6 +31,15 @@ LL | struct TupleStruct<S, T>(S, T);
 ...
 LL |     TupleStruct(_) = TupleStruct(1, 2);
    |     ^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     TupleStruct(_, _) = TupleStruct(1, 2);
+   |                  ^^^
+help: use `..` to ignore all fields
+   |
+LL |     TupleStruct(..) = TupleStruct(1, 2);
+   |                 ^^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/tuple_struct_destructure_fail.rs:34:5
@@ -49,6 +58,15 @@ LL |     SingleVariant(S, T)
 ...
 LL |     Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2);
+   |                          ^^^
+help: use `..` to ignore all fields
+   |
+LL |     Enum::SingleVariant(..) = Enum::SingleVariant(1, 2);
+   |                         ^^
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/tuple_struct_destructure_fail.rs:40:12
diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr
index a3610099294..832eba69722 100644
--- a/src/test/ui/error-codes/E0023.stderr
+++ b/src/test/ui/error-codes/E0023.stderr
@@ -6,6 +6,11 @@ LL |     Apple(String, String),
 ...
 LL |         Fruit::Apple(a) => {},
    |         ^^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Fruit::Apple(a, _) => {},
+   |                       ^^^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/E0023.rs:12:9
@@ -34,7 +39,7 @@ LL |     Orange((String, String)),
 LL |         Fruit::Orange(a, b) => {},
    |         ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2
    |
-help: missing parenthesis
+help: missing parentheses
    |
 LL |         Fruit::Orange((a, b)) => {},
    |                       ^    ^
@@ -48,7 +53,7 @@ LL |     Banana(()),
 LL |         Fruit::Banana() => {},
    |         ^^^^^^^^^^^^^^^ expected 1 field, found 0
    |
-help: missing parenthesis
+help: missing parentheses
    |
 LL |         Fruit::Banana(()) => {},
    |                      ^  ^
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
index 6e8ea6bf618..9bdbf0bf9f4 100644
--- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -17,6 +17,15 @@ LL | struct P<T>(T); // 1 type parameter wanted
 ...
 LL |     let P() = U {};
    |         ^^^ expected 1 field, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     let P(_) = U {};
+   |           ^
+help: use `..` to ignore all fields
+   |
+LL |     let P(..) = U {};
+   |           ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr
index 0a9c868af7a..a1e8ec1677d 100644
--- a/src/test/ui/issues/issue-72574-2.stderr
+++ b/src/test/ui/issues/issue-72574-2.stderr
@@ -26,6 +26,11 @@ LL | struct Binder(i32, i32, i32);
 ...
 LL |         Binder(_a, _x @ ..) => {}
    |         ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Binder(_a, _x @ .., _) => {}
+   |                           ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr
index c2298d6fbbf..37839482b31 100644
--- a/src/test/ui/match/match-pattern-field-mismatch.stderr
+++ b/src/test/ui/match/match-pattern-field-mismatch.stderr
@@ -6,6 +6,15 @@ LL |         Rgb(usize, usize, usize),
 ...
 LL |           Color::Rgb(_, _) => { }
    |           ^^^^^^^^^^^^^^^^ expected 3 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |           Color::Rgb(_, _, _) => { }
+   |                          ^^^
+help: use `..` to ignore all fields
+   |
+LL |           Color::Rgb(..) => { }
+   |                      ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr
index cbc90b5397d..f7644c19ea0 100644
--- a/src/test/ui/pattern/issue-74539.stderr
+++ b/src/test/ui/pattern/issue-74539.stderr
@@ -26,6 +26,11 @@ LL |     A(u8, u8),
 ...
 LL |         E::A(x @ ..) => {
    |         ^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::A(x @ .., _) => {
+   |                    ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs
new file mode 100644
index 00000000000..ed852a47bb4
--- /dev/null
+++ b/src/test/ui/pattern/pat-tuple-underfield.rs
@@ -0,0 +1,55 @@
+struct S(i32, f32);
+enum E {
+    S(i32, f32),
+}
+struct Point4(i32, i32, i32, i32);
+
+fn main() {
+    match S(0, 1.0) {
+        S(x) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+    }
+    match S(0, 1.0) {
+        S(_) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match S(0, 1.0) {
+        S() => {}
+        //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+
+    match E::S(0, 1.0) {
+        E::S(x) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+    }
+    match E::S(0, 1.0) {
+        E::S(_) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match E::S(0, 1.0) {
+        E::S() => {}
+        //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match E::S(0, 1.0) {
+        E::S => {}
+        //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S`
+        //~| HELP use the tuple variant pattern syntax instead
+    }
+
+    match Point4(0, 1, 2, 3) {
+        Point4(   a   ,     _    ) => {}
+        //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore the rest of the fields
+    }
+}
diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr
new file mode 100644
index 00000000000..76323d9a7bf
--- /dev/null
+++ b/src/test/ui/pattern/pat-tuple-underfield.stderr
@@ -0,0 +1,131 @@
+error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S`
+  --> $DIR/pat-tuple-underfield.rs:44:9
+   |
+LL |     S(i32, f32),
+   |     ----------- `E::S` defined here
+...
+LL |         E::S => {}
+   |         ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)`
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:9:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S(x) => {}
+   |         ^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(x, _) => {}
+   |            ^^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:14:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S(_) => {}
+   |         ^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(_, _) => {}
+   |            ^^^
+help: use `..` to ignore all fields
+   |
+LL |         S(..) => {}
+   |           ^^
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:20:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S() => {}
+   |         ^^^ expected 2 fields, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(_, _) => {}
+   |           ^^^^
+help: use `..` to ignore all fields
+   |
+LL |         S(..) => {}
+   |           ^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:27:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S(x) => {}
+   |         ^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(x, _) => {}
+   |               ^^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:32:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S(_) => {}
+   |         ^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(_, _) => {}
+   |               ^^^
+help: use `..` to ignore all fields
+   |
+LL |         E::S(..) => {}
+   |              ^^
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:38:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S() => {}
+   |         ^^^^^^ expected 2 fields, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(_, _) => {}
+   |              ^^^^
+help: use `..` to ignore all fields
+   |
+LL |         E::S(..) => {}
+   |              ^^
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+  --> $DIR/pat-tuple-underfield.rs:50:9
+   |
+LL | struct Point4(i32, i32, i32, i32);
+   | ---------------------------------- tuple struct defined here
+...
+LL |         Point4(   a   ,     _    ) => {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 4 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Point4(   a   ,     _    , _, _) => {}
+   |                                  ^^^^^^
+help: use `..` to ignore the rest of the fields
+   |
+LL |         Point4(   a   ,     _    , ..) => {}
+   |                                  ^^^^
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0023, E0532.
+For more information about an error, try `rustc --explain E0023`.