about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2019-11-01 15:44:58 +0000
committerNadrieril <nadrieril+git@gmail.com>2019-11-01 15:44:58 +0000
commit403d6bd995dc6a5e708dfe28f36e900ff94723e1 (patch)
treee8ca53ad501b70f408c65816486c08145668396e
parent2665b6434e6c851f6bffecf83e35db22ee6bf6bd (diff)
downloadrust-403d6bd995dc6a5e708dfe28f36e900ff94723e1.tar.gz
rust-403d6bd995dc6a5e708dfe28f36e900ff94723e1.zip
Abstract out pattern stacks to make the code more legible
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs122
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs11
2 files changed, 92 insertions, 41 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 1a619388f61..8382ddeabc6 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -342,16 +342,69 @@ impl<'tcx> Pat<'tcx> {
     }
 }
 
-/// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]`
-/// works well for each row.
-pub struct Matrix<'p, 'tcx>(Vec<SmallVec<[&'p Pat<'tcx>; 2]>>);
+/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
+/// works well.
+#[derive(Debug, Clone)]
+pub struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>);
+
+impl<'p, 'tcx> PatStack<'p, 'tcx> {
+    pub fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+        PatStack(smallvec![pat])
+    }
+
+    fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
+        PatStack(vec)
+    }
+
+    fn from_slice(s: &[&'p Pat<'tcx>]) -> Self {
+        PatStack(SmallVec::from_slice(s))
+    }
+
+    fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    fn head(&self) -> &'p Pat<'tcx> {
+        self.0[0]
+    }
+
+    fn to_tail(&self) -> Self {
+        PatStack::from_slice(&self.0[1..])
+    }
+
+    fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
+        self.0.iter().map(|p| *p)
+    }
+}
+
+impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
+    fn default() -> Self {
+        PatStack(smallvec![])
+    }
+}
+
+impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = &'p Pat<'tcx>>,
+    {
+        PatStack(iter.into_iter().collect())
+    }
+}
+
+/// A 2D matrix.
+pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
 
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
     pub fn empty() -> Self {
         Matrix(vec![])
     }
 
-    pub fn push(&mut self, row: SmallVec<[&'p Pat<'tcx>; 2]>) {
+    pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
         self.0.push(row)
     }
 }
@@ -399,10 +452,10 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
     }
 }
 
-impl<'p, 'tcx> FromIterator<SmallVec<[&'p Pat<'tcx>; 2]>> for Matrix<'p, 'tcx> {
+impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
     fn from_iter<T>(iter: T) -> Self
     where
-        T: IntoIterator<Item = SmallVec<[&'p Pat<'tcx>; 2]>>,
+        T: IntoIterator<Item = PatStack<'p, 'tcx>>,
     {
         Matrix(iter.into_iter().collect())
     }
@@ -1226,7 +1279,7 @@ fn compute_missing_ctors<'tcx>(
 pub fn is_useful<'p, 'a, 'tcx>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
-    v: &[&Pat<'tcx>],
+    v: &PatStack<'_, 'tcx>,
     witness: WitnessPreference,
     hir_id: HirId,
 ) -> Usefulness<'tcx> {
@@ -1253,9 +1306,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
     let (ty, span) = rows
         .iter()
-        .map(|r| (r[0].ty, r[0].span))
+        .map(|r| (r.head().ty, r.head().span))
         .find(|(ty, _)| !ty.references_error())
-        .unwrap_or((v[0].ty, v[0].span));
+        .unwrap_or((v.head().ty, v.head().span));
     let pcx = PatCtxt {
         // TyErr is used to represent the type of wildcard patterns matching
         // against inaccessible (private) fields of structs, so that we won't
@@ -1277,13 +1330,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
         // introducing uninhabited patterns for inaccessible fields. We
         // need to figure out how to model that.
         ty,
-        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))),
+        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r.head()).chain(Some(v.head()))),
         span,
     };
 
-    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
+    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
 
-    if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
+    if let Some(constructors) = pat_constructors(cx, v.head(), pcx) {
         debug!("is_useful - expanding constructors: {:#?}", constructors);
         split_grouped_constructors(
             cx.tcx,
@@ -1303,7 +1356,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
         let used_ctors: Vec<Constructor<'_>> = rows
             .iter()
-            .flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
+            .flat_map(|row| pat_constructors(cx, row.head(), pcx).unwrap_or(vec![]))
             .collect();
         debug!("used_ctors = {:#?}", used_ctors);
         // `all_ctors` are all the constructors for the given type, which
@@ -1372,11 +1425,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
         } else {
             let matrix = rows
                 .iter()
-                .filter_map(|r| {
-                    if r[0].is_wildcard() { Some(SmallVec::from_slice(&r[1..])) } else { None }
-                })
+                .filter_map(|r| if r.head().is_wildcard() { Some(r.to_tail()) } else { None })
                 .collect();
-            match is_useful(cx, &matrix, &v[1..], witness, hir_id) {
+            match is_useful(cx, &matrix, &v.to_tail(), witness, hir_id) {
                 UsefulWithWitness(pats) => {
                     let cx = &*cx;
                     // In this case, there's at least one "free"
@@ -1473,7 +1524,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
 fn is_useful_specialized<'p, 'a, 'tcx>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     &Matrix(ref m): &Matrix<'p, 'tcx>,
-    v: &[&Pat<'tcx>],
+    v: &PatStack<'_, 'tcx>,
     ctor: Constructor<'tcx>,
     lty: Ty<'tcx>,
     witness: WitnessPreference,
@@ -1787,7 +1838,7 @@ fn split_grouped_constructors<'p, 'tcx>(
                 let row_borders = m
                     .iter()
                     .flat_map(|row| {
-                        IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len()))
+                        IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len()))
                     })
                     .flat_map(|(range, row_len)| {
                         let intersection = ctor_range.intersection(&range);
@@ -1933,7 +1984,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
     subpatterns: &'p [FieldPat<'tcx>],
     wild_patterns: &[&'p Pat<'tcx>],
     is_non_exhaustive: bool,
-) -> SmallVec<[&'p Pat<'tcx>; 2]> {
+) -> PatStack<'p, 'tcx> {
     let mut result = SmallVec::from_slice(wild_patterns);
 
     for subpat in subpatterns {
@@ -1943,7 +1994,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
     }
 
     debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
-    result
+    PatStack::from_vec(result)
 }
 
 /// This is the main specialization step. It expands the first pattern in the given row
@@ -1954,20 +2005,20 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
 /// different patterns.
 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 /// fields filled with wild patterns.
-fn specialize<'p, 'a: 'p, 'tcx>(
+fn specialize<'p, 'a: 'p, 'q: 'p, 'tcx>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    r: &[&'p Pat<'tcx>],
+    r: &PatStack<'q, 'tcx>,
     constructor: &Constructor<'tcx>,
     wild_patterns: &[&'p Pat<'tcx>],
-) -> Option<SmallVec<[&'p Pat<'tcx>; 2]>> {
-    let pat = &r[0];
+) -> Option<PatStack<'p, 'tcx>> {
+    let pat = r.head();
 
     let head = match *pat.kind {
         PatKind::AscribeUserType { ref subpattern, .. } => {
-            specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns)
+            specialize(cx, &PatStack::from_pattern(subpattern), constructor, wild_patterns)
         }
 
-        PatKind::Binding { .. } | PatKind::Wild => Some(SmallVec::from_slice(wild_patterns)),
+        PatKind::Binding { .. } | PatKind::Wild => Some(PatStack::from_slice(wild_patterns)),
 
         PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let ref variant = adt_def.variants[variant_index];
@@ -1981,7 +2032,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
             Some(patterns_for_variant(cx, subpatterns, wild_patterns, false))
         }
 
-        PatKind::Deref { ref subpattern } => Some(smallvec![subpattern]),
+        PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
 
         PatKind::Constant { value } if constructor.is_slice() => {
             // We extract an `Option` for the pointer because slices of zero
@@ -2051,7 +2102,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
                         let (pat_lo, pat_hi) = pat.range.into_inner();
                         let (ctor_lo, ctor_hi) = ctor.range.into_inner();
                         assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
-                        smallvec![]
+                        PatStack::default()
                     }),
                     _ => None,
                 }
@@ -2062,7 +2113,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
                 // range so intersection actually devolves into being covered
                 // by the pattern.
                 match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) {
-                    Ok(true) => Some(smallvec![]),
+                    Ok(true) => Some(PatStack::default()),
                     Ok(false) | Err(ErrorReported) => None,
                 }
             }
@@ -2104,7 +2155,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
                     suffix,
                     cx.param_env,
                 ) {
-                    Ok(true) => Some(smallvec![]),
+                    Ok(true) => Some(PatStack::default()),
                     Ok(false) => None,
                     Err(ErrorReported) => None,
                 }
@@ -2116,10 +2167,11 @@ fn specialize<'p, 'a: 'p, 'tcx>(
             bug!("support for or-patterns has not been fully implemented yet.");
         }
     };
-    debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
+    debug!("specialize({:#?}, {:#?}) = {:#?}", r.head(), wild_patterns, head);
 
-    head.map(|mut head| {
-        head.extend_from_slice(&r[1..]);
-        head
+    head.map(|head| {
+        let mut head = head.0;
+        head.extend_from_slice(&r.0[1..]);
+        PatStack::from_vec(head)
     })
 }
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index ecfe43c6574..9d370554e86 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -1,6 +1,6 @@
 use super::_match::Usefulness::*;
 use super::_match::WitnessPreference::*;
-use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix};
+use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
 
 use super::{PatCtxt, PatKind, PatternError};
 
@@ -16,7 +16,6 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::HirId;
 use rustc::hir::{self, Pat};
 
-use smallvec::smallvec;
 use std::slice;
 
 use syntax_pos::{MultiSpan, Span, DUMMY_SP};
@@ -251,7 +250,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
                 .flat_map(|arm| &arm.0)
-                .map(|pat| smallvec![pat.0])
+                .map(|pat| PatStack::from_pattern(pat.0))
                 .collect();
             let scrut_ty = self.tables.node_type(scrut.hir_id);
             check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
@@ -267,7 +266,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
             let pattern = patcx.lower_pattern(pat);
             let pattern_ty = pattern.ty;
             let pattern = expand_pattern(cx, pattern);
-            let pats: Matrix<'_, '_> = vec![smallvec![&pattern]].into_iter().collect();
+            let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(&pattern)].into_iter().collect();
 
             let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
                 Ok(_) => return,
@@ -411,7 +410,7 @@ fn check_arms<'tcx>(
     let mut catchall = None;
     for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
         for &(pat, hir_pat) in pats {
-            let v = smallvec![pat];
+            let v = PatStack::from_pattern(pat);
 
             match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
                 NotUseful => {
@@ -493,7 +492,7 @@ fn check_not_useful(
     hir_id: HirId,
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
     let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
-    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness, hir_id) {
+    match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
             vec![wild_pattern]