Abstract out pattern stacks to make the code more legible
This commit is contained in:
parent
2665b6434e
commit
403d6bd995
2 changed files with 92 additions and 41 deletions
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue