From 403d6bd995dc6a5e708dfe28f36e900ff94723e1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 1 Nov 2019 15:44:58 +0000 Subject: [PATCH] Abstract out pattern stacks to make the code more legible --- src/librustc_mir/hair/pattern/_match.rs | 122 +++++++++++++------ src/librustc_mir/hair/pattern/check_match.rs | 11 +- 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 1a619388f611..8382ddeabc6f 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; 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> { + 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(iter: T) -> Self + where + T: IntoIterator>, + { + PatStack(iter.into_iter().collect()) + } +} + +/// A 2D matrix. +pub struct Matrix<'p, 'tcx>(Vec>); 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; 2]>> for Matrix<'p, 'tcx> { +impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { fn from_iter(iter: T) -> Self where - T: IntoIterator; 2]>>, + T: IntoIterator>, { 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> = 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; 2]>> { - let pat = &r[0]; +) -> Option> { + 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 ecfe43c65747..9d370554e86b 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>> { 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]