about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-24 22:42:45 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-09-24 22:42:45 +0200
commit7b71abdb5490665e6e1f26486da0067904c1cd60 (patch)
tree0b08172b914801e2042daf39fc5a1e1fa8558563 /src
parent6ef275e6c3cb1384ec78128eceeb4963ff788dca (diff)
downloadrust-7b71abdb5490665e6e1f26486da0067904c1cd60.tar.gz
rust-7b71abdb5490665e6e1f26486da0067904c1cd60.zip
Fix #64744 -- handle zero sub-pats case.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/pat.rs59
-rw-r--r--src/test/ui/error-codes/E0023.rs3
-rw-r--r--src/test/ui/error-codes/E0023.stderr15
3 files changed, 62 insertions, 15 deletions
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index d687a5084e2..2cd8507d753 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         } else {
             // Pattern has wrong number of fields.
-            self.e0023(pat.span, res, &subpats, &variant.fields, expected);
+            self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
             on_error();
             return tcx.types.err;
         }
@@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat_span: Span,
         res: Res,
+        qpath: &hir::QPath,
         subpats: &'tcx [P<Pat>],
         fields: &[ty::FieldDef],
         expected: Ty<'tcx>
     ) {
         let subpats_ending = pluralise!(subpats.len());
         let fields_ending = pluralise!(fields.len());
-        let missing_parenthesis = match expected.sty {
-            ty::Adt(_, substs) if fields.len() == 1 => {
-                let field_ty = fields[0].ty(self.tcx, substs);
-                match field_ty.sty {
-                    ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
-                    _ => false,
-                }
-            }
-            _ => false,
-        };
         let res_span = self.tcx.def_span(res.def_id());
         let mut err = struct_span_err!(
             self.tcx.sess,
@@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ))
             .span_label(res_span, format!("{} defined here", res.descr()));
 
+        // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
+        // 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.sty {
+            ty::Adt(_, substs) if fields.len() == 1 => {
+                let field_ty = fields[0].ty(self.tcx, substs);
+                match field_ty.sty {
+                    ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
+                    _ => false,
+                }
+            }
+            _ => false,
+        };
         if missing_parenthesis {
+            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
+                //   |
+                // L |     let A(()) = A(());
+                //   |          ^  ^
+                [] => {
+                    let qpath_span = match qpath {
+                        hir::QPath::Resolved(_, path) => path.span,
+                        hir::QPath::TypeRelative(_, ps) => ps.ident.span,
+                    };
+                    (qpath_span.shrink_to_hi(), pat_span)
+                },
+                // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
+                // last sub-pattern. In the case of `A(x)` the first and last may coincide.
+                // This looks like:
+                //
+                // help: missing parenthesis
+                //   |
+                // L |     let A((x, y)) = A((1, 2));
+                //   |           ^    ^
+                [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
+            };
             err.multipart_suggestion(
                 "missing parenthesis",
-                vec![(subpats[0].span.shrink_to_lo(), "(".to_string()),
-                    (subpats[subpats.len()-1].span.shrink_to_hi(), ")".to_string())],
+                vec![
+                    (left, "(".to_string()),
+                    (right.shrink_to_hi(), ")".to_string()),
+                ],
                 Applicability::MachineApplicable,
             );
         }
diff --git a/src/test/ui/error-codes/E0023.rs b/src/test/ui/error-codes/E0023.rs
index dc421e060e8..7ac22bb7109 100644
--- a/src/test/ui/error-codes/E0023.rs
+++ b/src/test/ui/error-codes/E0023.rs
@@ -2,9 +2,9 @@ enum Fruit {
     Apple(String, String),
     Pear(u32),
     Orange((String, String)),
+    Banana(()),
 }
 
-
 fn main() {
     let x = Fruit::Apple(String::new(), String::new());
     match x {
@@ -12,5 +12,6 @@ fn main() {
         Fruit::Apple(a, b, c) => {}, //~ ERROR E0023
         Fruit::Pear(1, 2) => {}, //~ ERROR E0023
         Fruit::Orange(a, b) => {}, //~ ERROR E0023
+        Fruit::Banana() => {}, //~ ERROR E0023
     }
 }
diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr
index 8ae7d01ed5f..dbce6003a2b 100644
--- a/src/test/ui/error-codes/E0023.stderr
+++ b/src/test/ui/error-codes/E0023.stderr
@@ -38,6 +38,19 @@ help: missing parenthesis
 LL |         Fruit::Orange((a, b)) => {},
    |                       ^    ^
 
-error: aborting due to 4 previous errors
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field
+  --> $DIR/E0023.rs:15:9
+   |
+LL |     Banana(()),
+   |     ---------- tuple variant defined here
+...
+LL |         Fruit::Banana() => {},
+   |         ^^^^^^^^^^^^^^^ expected 1 field, found 0
+help: missing parenthesis
+   |
+LL |         Fruit::Banana(()) => {},
+   |                      ^  ^
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0023`.