about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-12-22 02:40:03 +0100
committerGitHub <noreply@github.com>2019-12-22 02:40:03 +0100
commit877dc9daa8eebee7a6e4dc5fc7df6770a086df59 (patch)
tree97f8f018315c532bc1aee3ee0fbaf84fa8366369 /src
parent35ff2f1df3ee2cd51edf2bbeddec474b970987fc (diff)
parent7353ff20d66267df821d9d161b914ef8fc513304 (diff)
downloadrust-877dc9daa8eebee7a6e4dc5fc7df6770a086df59.tar.gz
rust-877dc9daa8eebee7a6e4dc5fc7df6770a086df59.zip
Rollup merge of #67439 - Centril:clean-hair-slice, r=matthewjasper
Cleanup `lower_pattern_unadjusted` & Improve slice pat typeck

Following up on https://github.com/rust-lang/rust/pull/67318, in this PR, the HAIR lowering of patterns (`lower_pattern_unadjusted`) is cleaned up with a focus on slice patterns (in particular, some dead code is removed). Moreover, `check_pat_slice` is refactored some more.

r? @matthewjasper
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs9
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs162
-rw-r--r--src/librustc_typeck/check/pat.rs87
3 files changed, 96 insertions, 162 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index c3720328506..f267be812c3 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -620,10 +620,11 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
 enum SliceKind {
     /// Patterns of length `n` (`[x, y]`).
     FixedLen(u64),
-    /// Patterns using the `..` notation (`[x, .., y]`). Captures any array constructor of `length
-    /// >= i + j`. In the case where `array_len` is `Some(_)`, this indicates that we only care
-    /// about the first `i` and the last `j` values of the array, and everything in between is a
-    /// wildcard `_`.
+    /// Patterns using the `..` notation (`[x, .., y]`).
+    /// Captures any array constructor of `length >= i + j`.
+    /// In the case where `array_len` is `Some(_)`,
+    /// this indicates that we only care about the first `i` and the last `j` values of the array,
+    /// and everything in between is a wildcard `_`.
     VarLen(u64, u64),
 }
 
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 7f15b3de5ef..9d0a67151fb 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -445,6 +445,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pat<'tcx> {
         let mut ty = self.tables.node_type(pat.hir_id);
 
+        if let ty::Error = ty.kind {
+            // Avoid ICEs (e.g., #50577 and #50585).
+            return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
+        }
+
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
 
@@ -544,57 +549,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                match ty.kind {
-                    ty::Ref(_, ty, _) =>
-                        PatKind::Deref {
-                            subpattern: Pat {
-                                ty,
-                                span: pat.span,
-                                kind: Box::new(self.slice_or_array_pattern(
-                                    pat.span, ty, prefix, slice, suffix))
-                            },
-                        },
-                    ty::Slice(..) |
-                    ty::Array(..) =>
-                        self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
-                    ty::Error => { // Avoid ICE
-                        return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
-                    }
-                    _ =>
-                        span_bug!(
-                            pat.span,
-                            "unexpanded type for vector pattern: {:?}",
-                            ty),
-                }
+                self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
             }
 
-            hir::PatKind::Tuple(ref subpatterns, ddpos) => {
-                match ty.kind {
-                    ty::Tuple(ref tys) => {
-                        let subpatterns =
-                            subpatterns.iter()
-                                       .enumerate_and_adjust(tys.len(), ddpos)
-                                       .map(|(i, subpattern)| FieldPat {
-                                            field: Field::new(i),
-                                            pattern: self.lower_pattern(subpattern)
-                                       })
-                                       .collect();
-
-                        PatKind::Leaf { subpatterns }
-                    }
-                    ty::Error => { // Avoid ICE (#50577)
-                        return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
-                    }
+            hir::PatKind::Tuple(ref pats, ddpos) => {
+                let tys = match ty.kind {
+                    ty::Tuple(ref tys) => tys,
                     _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty),
-                }
+                };
+                let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
+                PatKind::Leaf { subpatterns }
             }
 
             hir::PatKind::Binding(_, id, ident, ref sub) => {
-                let var_ty = self.tables.node_type(pat.hir_id);
-                if let ty::Error = var_ty.kind {
-                    // Avoid ICE
-                    return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
-                };
                 let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
                                                          .expect("missing binding mode");
                 let (mutability, mode) = match bm {
@@ -609,13 +576,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
                 // A ref x pattern is the same node used for x, and as such it has
                 // x's type, which is &T, where we want T (the type being matched).
+                let var_ty = ty;
                 if let ty::BindByReference(_) = bm {
                     if let ty::Ref(_, rty, _) = ty.kind {
                         ty = rty;
                     } else {
                         bug!("`ref {}` has wrong type {}", ident, ty);
                     }
-                }
+                };
 
                 PatKind::Binding {
                     mutability,
@@ -627,28 +595,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 }
             }
 
-            hir::PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
+            hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => {
                 let res = self.tables.qpath_res(qpath, pat.hir_id);
                 let adt_def = match ty.kind {
                     ty::Adt(adt_def, _) => adt_def,
-                    ty::Error => { // Avoid ICE (#50585)
-                        return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
-                    }
-                    _ => span_bug!(pat.span,
-                                   "tuple struct pattern not applied to an ADT {:?}",
-                                   ty),
+                    _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty),
                 };
                 let variant_def = adt_def.variant_of_res(res);
-
-                let subpatterns =
-                        subpatterns.iter()
-                                   .enumerate_and_adjust(variant_def.fields.len(), ddpos)
-                                   .map(|(i, field)| FieldPat {
-                                       field: Field::new(i),
-                                       pattern: self.lower_pattern(field),
-                                   })
-                    .collect();
-
+                let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
                 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
             }
 
@@ -668,11 +622,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
             }
 
-            hir::PatKind::Or(ref pats) => {
-                PatKind::Or {
-                    pats: pats.iter().map(|p| self.lower_pattern(p)).collect(),
-                }
-            }
+            hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
         };
 
         Pat {
@@ -682,80 +632,50 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         }
     }
 
+    fn lower_tuple_subpats(
+        &mut self,
+        pats: &'tcx [P<hir::Pat>],
+        expected_len: usize,
+        gap_pos: Option<usize>,
+    ) -> Vec<FieldPat<'tcx>> {
+        pats.iter()
+            .enumerate_and_adjust(expected_len, gap_pos)
+            .map(|(i, subpattern)| FieldPat {
+                field: Field::new(i),
+                pattern: self.lower_pattern(subpattern)
+            })
+            .collect()
+    }
+
     fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pat<'tcx>> {
         pats.iter().map(|p| self.lower_pattern(p)).collect()
     }
 
-    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pat<'tcx>>
-    {
+    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pat<'tcx>> {
         pat.as_ref().map(|p| self.lower_pattern(p))
     }
 
-    fn flatten_nested_slice_patterns(
-        &mut self,
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>)
-        -> (Vec<Pat<'tcx>>, Option<Pat<'tcx>>, Vec<Pat<'tcx>>)
-    {
-        let orig_slice = match slice {
-            Some(orig_slice) => orig_slice,
-            None => return (prefix, slice, suffix)
-        };
-        let orig_prefix = prefix;
-        let orig_suffix = suffix;
-
-        // dance because of intentional borrow-checker stupidity.
-        let kind = *orig_slice.kind;
-        match kind {
-            PatKind::Slice { prefix, slice, mut suffix } |
-            PatKind::Array { prefix, slice, mut suffix } => {
-                let mut orig_prefix = orig_prefix;
-
-                orig_prefix.extend(prefix);
-                suffix.extend(orig_suffix);
-
-                (orig_prefix, slice, suffix)
-            }
-            _ => {
-                (orig_prefix, Some(Pat {
-                    kind: box kind, ..orig_slice
-                }), orig_suffix)
-            }
-        }
-    }
-
     fn slice_or_array_pattern(
         &mut self,
         span: Span,
         ty: Ty<'tcx>,
         prefix: &'tcx [P<hir::Pat>],
         slice: &'tcx Option<P<hir::Pat>>,
-        suffix: &'tcx [P<hir::Pat>])
-        -> PatKind<'tcx>
-    {
+        suffix: &'tcx [P<hir::Pat>],
+    ) -> PatKind<'tcx> {
         let prefix = self.lower_patterns(prefix);
         let slice = self.lower_opt_pattern(slice);
         let suffix = self.lower_patterns(suffix);
-        let (prefix, slice, suffix) =
-            self.flatten_nested_slice_patterns(prefix, slice, suffix);
-
         match ty.kind {
-            ty::Slice(..) => {
-                // matching a slice or fixed-length array
-                PatKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
-            }
-
+            // Matching a slice, `[T]`.
+            ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
+            // Fixed-length array, `[T; len]`.
             ty::Array(_, len) => {
-                // fixed-length array
                 let len = len.eval_usize(self.tcx, self.param_env);
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
-                PatKind::Array { prefix: prefix, slice: slice, suffix: suffix }
-            }
-
-            _ => {
-                span_bug!(span, "bad slice pattern type {:?}", ty);
+                PatKind::Array { prefix, slice, suffix }
             }
+            _ => span_bug!(span, "bad slice pattern type {:?}", ty),
         }
     }
 
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 11f744e9761..ec6439c6d77 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1174,47 +1174,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         def_bm: BindingMode,
         discrim_span: Option<Span>,
     ) -> Ty<'tcx> {
-        let tcx = self.tcx;
-        let expected_ty = self.structurally_resolved_type(span, expected);
-        let (inner_ty, slice_ty) = match expected_ty.kind {
+        let err = self.tcx.types.err;
+        let expected = self.structurally_resolved_type(span, expected);
+        let (inner_ty, slice_ty, expected) = match expected.kind {
             // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
-            ty::Array(inner_ty, size) => {
-                let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
-                    // Now we know the length...
-                    let min_len = before.len() as u64 + after.len() as u64;
-                    if slice.is_none() {
-                        // ...and since there is no variable-length pattern,
-                        // we require an exact match between the number of elements
-                        // in the array pattern and as provided by the matched type.
-                        if min_len != size {
-                            self.error_scrutinee_inconsistent_length(span, min_len, size)
-                        }
-                        tcx.types.err
-                    } else if let Some(rest) = size.checked_sub(min_len) {
-                        // The variable-length pattern was there,
-                        // so it has an array type with the remaining elements left as its size...
-                        tcx.mk_array(inner_ty, rest)
-                    } else {
-                        // ...however, in this case, there were no remaining elements.
-                        // That is, the slice pattern requires more than the array type offers.
-                        self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size);
-                        tcx.types.err
-                    }
-                } else {
-                    // No idea what the length is, which happens if we have e.g.,
-                    // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
-                    self.error_scrutinee_unfixed_length(span);
-                    tcx.types.err
-                };
-                (inner_ty, slice_ty)
+            ty::Array(inner_ty, len) => {
+                let min = before.len() as u64 + after.len() as u64;
+                let slice_ty = self.check_array_pat_len(span, slice, len, min)
+                    .map_or(err, |len| self.tcx.mk_array(inner_ty, len));
+                (inner_ty, slice_ty, expected)
             }
-            ty::Slice(inner_ty) => (inner_ty, expected_ty),
+            ty::Slice(inner_ty) => (inner_ty, expected, expected),
             // The expected type must be an array or slice, but was neither, so error.
             _ => {
-                if !expected_ty.references_error() {
-                    self.error_expected_array_or_slice(span, expected_ty);
+                if !expected.references_error() {
+                    self.error_expected_array_or_slice(span, expected);
                 }
-                (tcx.types.err, tcx.types.err)
+                (err, err, err)
             }
         };
 
@@ -1230,7 +1206,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for elt in after {
             self.check_pat(&elt, inner_ty, def_bm, discrim_span);
         }
-        expected_ty
+        expected
+    }
+
+    /// Type check the length of an array pattern.
+    ///
+    /// Return the length of the variable length pattern,
+    /// if it exists and there are no errors.
+    fn check_array_pat_len(
+        &self,
+        span: Span,
+        slice: Option<&'tcx Pat>,
+        len: &ty::Const<'tcx>,
+        min_len: u64,
+    ) -> Option<u64> {
+        if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
+            // Now we know the length...
+            if slice.is_none() {
+                // ...and since there is no variable-length pattern,
+                // we require an exact match between the number of elements
+                // in the array pattern and as provided by the matched type.
+                if min_len != len {
+                    self.error_scrutinee_inconsistent_length(span, min_len, len);
+                }
+            } else if let r @ Some(_) = len.checked_sub(min_len) {
+                // The variable-length pattern was there,
+                // so it has an array type with the remaining elements left as its size...
+                return r;
+            } else {
+                // ...however, in this case, there were no remaining elements.
+                // That is, the slice pattern requires more than the array type offers.
+                self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len);
+            }
+        } else {
+            // No idea what the length is, which happens if we have e.g.,
+            // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
+            self.error_scrutinee_unfixed_length(span);
+        }
+        None
     }
 
     fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {