Skip to content

Commit 403d6bd

Browse files
committed
Abstract out pattern stacks to make the code more legible
1 parent 2665b64 commit 403d6bd

File tree

2 files changed

+92
-41
lines changed

2 files changed

+92
-41
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -342,16 +342,69 @@ impl<'tcx> Pat<'tcx> {
342342
}
343343
}
344344

345-
/// A 2D matrix. Nx1 matrices are very common, which is why `SmallVec[_; 2]`
346-
/// works well for each row.
347-
pub struct Matrix<'p, 'tcx>(Vec<SmallVec<[&'p Pat<'tcx>; 2]>>);
345+
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
346+
/// works well.
347+
#[derive(Debug, Clone)]
348+
pub struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>);
349+
350+
impl<'p, 'tcx> PatStack<'p, 'tcx> {
351+
pub fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
352+
PatStack(smallvec![pat])
353+
}
354+
355+
fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
356+
PatStack(vec)
357+
}
358+
359+
fn from_slice(s: &[&'p Pat<'tcx>]) -> Self {
360+
PatStack(SmallVec::from_slice(s))
361+
}
362+
363+
fn is_empty(&self) -> bool {
364+
self.0.is_empty()
365+
}
366+
367+
fn len(&self) -> usize {
368+
self.0.len()
369+
}
370+
371+
fn head(&self) -> &'p Pat<'tcx> {
372+
self.0[0]
373+
}
374+
375+
fn to_tail(&self) -> Self {
376+
PatStack::from_slice(&self.0[1..])
377+
}
378+
379+
fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
380+
self.0.iter().map(|p| *p)
381+
}
382+
}
383+
384+
impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
385+
fn default() -> Self {
386+
PatStack(smallvec![])
387+
}
388+
}
389+
390+
impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
391+
fn from_iter<T>(iter: T) -> Self
392+
where
393+
T: IntoIterator<Item = &'p Pat<'tcx>>,
394+
{
395+
PatStack(iter.into_iter().collect())
396+
}
397+
}
398+
399+
/// A 2D matrix.
400+
pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
348401

349402
impl<'p, 'tcx> Matrix<'p, 'tcx> {
350403
pub fn empty() -> Self {
351404
Matrix(vec![])
352405
}
353406

354-
pub fn push(&mut self, row: SmallVec<[&'p Pat<'tcx>; 2]>) {
407+
pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
355408
self.0.push(row)
356409
}
357410
}
@@ -399,10 +452,10 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
399452
}
400453
}
401454

402-
impl<'p, 'tcx> FromIterator<SmallVec<[&'p Pat<'tcx>; 2]>> for Matrix<'p, 'tcx> {
455+
impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
403456
fn from_iter<T>(iter: T) -> Self
404457
where
405-
T: IntoIterator<Item = SmallVec<[&'p Pat<'tcx>; 2]>>,
458+
T: IntoIterator<Item = PatStack<'p, 'tcx>>,
406459
{
407460
Matrix(iter.into_iter().collect())
408461
}
@@ -1226,7 +1279,7 @@ fn compute_missing_ctors<'tcx>(
12261279
pub fn is_useful<'p, 'a, 'tcx>(
12271280
cx: &mut MatchCheckCtxt<'a, 'tcx>,
12281281
matrix: &Matrix<'p, 'tcx>,
1229-
v: &[&Pat<'tcx>],
1282+
v: &PatStack<'_, 'tcx>,
12301283
witness: WitnessPreference,
12311284
hir_id: HirId,
12321285
) -> Usefulness<'tcx> {
@@ -1253,9 +1306,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
12531306

12541307
let (ty, span) = rows
12551308
.iter()
1256-
.map(|r| (r[0].ty, r[0].span))
1309+
.map(|r| (r.head().ty, r.head().span))
12571310
.find(|(ty, _)| !ty.references_error())
1258-
.unwrap_or((v[0].ty, v[0].span));
1311+
.unwrap_or((v.head().ty, v.head().span));
12591312
let pcx = PatCtxt {
12601313
// TyErr is used to represent the type of wildcard patterns matching
12611314
// against inaccessible (private) fields of structs, so that we won't
@@ -1277,13 +1330,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
12771330
// introducing uninhabited patterns for inaccessible fields. We
12781331
// need to figure out how to model that.
12791332
ty,
1280-
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))),
1333+
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r.head()).chain(Some(v.head()))),
12811334
span,
12821335
};
12831336

1284-
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
1337+
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
12851338

1286-
if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
1339+
if let Some(constructors) = pat_constructors(cx, v.head(), pcx) {
12871340
debug!("is_useful - expanding constructors: {:#?}", constructors);
12881341
split_grouped_constructors(
12891342
cx.tcx,
@@ -1303,7 +1356,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
13031356

13041357
let used_ctors: Vec<Constructor<'_>> = rows
13051358
.iter()
1306-
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
1359+
.flat_map(|row| pat_constructors(cx, row.head(), pcx).unwrap_or(vec![]))
13071360
.collect();
13081361
debug!("used_ctors = {:#?}", used_ctors);
13091362
// `all_ctors` are all the constructors for the given type, which
@@ -1372,11 +1425,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
13721425
} else {
13731426
let matrix = rows
13741427
.iter()
1375-
.filter_map(|r| {
1376-
if r[0].is_wildcard() { Some(SmallVec::from_slice(&r[1..])) } else { None }
1377-
})
1428+
.filter_map(|r| if r.head().is_wildcard() { Some(r.to_tail()) } else { None })
13781429
.collect();
1379-
match is_useful(cx, &matrix, &v[1..], witness, hir_id) {
1430+
match is_useful(cx, &matrix, &v.to_tail(), witness, hir_id) {
13801431
UsefulWithWitness(pats) => {
13811432
let cx = &*cx;
13821433
// In this case, there's at least one "free"
@@ -1473,7 +1524,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
14731524
fn is_useful_specialized<'p, 'a, 'tcx>(
14741525
cx: &mut MatchCheckCtxt<'a, 'tcx>,
14751526
&Matrix(ref m): &Matrix<'p, 'tcx>,
1476-
v: &[&Pat<'tcx>],
1527+
v: &PatStack<'_, 'tcx>,
14771528
ctor: Constructor<'tcx>,
14781529
lty: Ty<'tcx>,
14791530
witness: WitnessPreference,
@@ -1787,7 +1838,7 @@ fn split_grouped_constructors<'p, 'tcx>(
17871838
let row_borders = m
17881839
.iter()
17891840
.flat_map(|row| {
1790-
IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len()))
1841+
IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len()))
17911842
})
17921843
.flat_map(|(range, row_len)| {
17931844
let intersection = ctor_range.intersection(&range);
@@ -1933,7 +1984,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
19331984
subpatterns: &'p [FieldPat<'tcx>],
19341985
wild_patterns: &[&'p Pat<'tcx>],
19351986
is_non_exhaustive: bool,
1936-
) -> SmallVec<[&'p Pat<'tcx>; 2]> {
1987+
) -> PatStack<'p, 'tcx> {
19371988
let mut result = SmallVec::from_slice(wild_patterns);
19381989

19391990
for subpat in subpatterns {
@@ -1943,7 +1994,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
19431994
}
19441995

19451996
debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
1946-
result
1997+
PatStack::from_vec(result)
19471998
}
19481999

19492000
/// 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>(
19542005
/// different patterns.
19552006
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
19562007
/// fields filled with wild patterns.
1957-
fn specialize<'p, 'a: 'p, 'tcx>(
2008+
fn specialize<'p, 'a: 'p, 'q: 'p, 'tcx>(
19582009
cx: &mut MatchCheckCtxt<'a, 'tcx>,
1959-
r: &[&'p Pat<'tcx>],
2010+
r: &PatStack<'q, 'tcx>,
19602011
constructor: &Constructor<'tcx>,
19612012
wild_patterns: &[&'p Pat<'tcx>],
1962-
) -> Option<SmallVec<[&'p Pat<'tcx>; 2]>> {
1963-
let pat = &r[0];
2013+
) -> Option<PatStack<'p, 'tcx>> {
2014+
let pat = r.head();
19642015

19652016
let head = match *pat.kind {
19662017
PatKind::AscribeUserType { ref subpattern, .. } => {
1967-
specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns)
2018+
specialize(cx, &PatStack::from_pattern(subpattern), constructor, wild_patterns)
19682019
}
19692020

1970-
PatKind::Binding { .. } | PatKind::Wild => Some(SmallVec::from_slice(wild_patterns)),
2021+
PatKind::Binding { .. } | PatKind::Wild => Some(PatStack::from_slice(wild_patterns)),
19712022

19722023
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
19732024
let ref variant = adt_def.variants[variant_index];
@@ -1981,7 +2032,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
19812032
Some(patterns_for_variant(cx, subpatterns, wild_patterns, false))
19822033
}
19832034

1984-
PatKind::Deref { ref subpattern } => Some(smallvec![subpattern]),
2035+
PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
19852036

19862037
PatKind::Constant { value } if constructor.is_slice() => {
19872038
// We extract an `Option` for the pointer because slices of zero
@@ -2051,7 +2102,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
20512102
let (pat_lo, pat_hi) = pat.range.into_inner();
20522103
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
20532104
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
2054-
smallvec![]
2105+
PatStack::default()
20552106
}),
20562107
_ => None,
20572108
}
@@ -2062,7 +2113,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
20622113
// range so intersection actually devolves into being covered
20632114
// by the pattern.
20642115
match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) {
2065-
Ok(true) => Some(smallvec![]),
2116+
Ok(true) => Some(PatStack::default()),
20662117
Ok(false) | Err(ErrorReported) => None,
20672118
}
20682119
}
@@ -2104,7 +2155,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
21042155
suffix,
21052156
cx.param_env,
21062157
) {
2107-
Ok(true) => Some(smallvec![]),
2158+
Ok(true) => Some(PatStack::default()),
21082159
Ok(false) => None,
21092160
Err(ErrorReported) => None,
21102161
}
@@ -2116,10 +2167,11 @@ fn specialize<'p, 'a: 'p, 'tcx>(
21162167
bug!("support for or-patterns has not been fully implemented yet.");
21172168
}
21182169
};
2119-
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
2170+
debug!("specialize({:#?}, {:#?}) = {:#?}", r.head(), wild_patterns, head);
21202171

2121-
head.map(|mut head| {
2122-
head.extend_from_slice(&r[1..]);
2123-
head
2172+
head.map(|head| {
2173+
let mut head = head.0;
2174+
head.extend_from_slice(&r.0[1..]);
2175+
PatStack::from_vec(head)
21242176
})
21252177
}

src/librustc_mir/hair/pattern/check_match.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::_match::Usefulness::*;
22
use super::_match::WitnessPreference::*;
3-
use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix};
3+
use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
44

55
use super::{PatCtxt, PatKind, PatternError};
66

@@ -16,7 +16,6 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
1616
use rustc::hir::HirId;
1717
use rustc::hir::{self, Pat};
1818

19-
use smallvec::smallvec;
2019
use std::slice;
2120

2221
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
@@ -251,7 +250,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
251250
.iter()
252251
.filter(|&&(_, guard)| guard.is_none())
253252
.flat_map(|arm| &arm.0)
254-
.map(|pat| smallvec![pat.0])
253+
.map(|pat| PatStack::from_pattern(pat.0))
255254
.collect();
256255
let scrut_ty = self.tables.node_type(scrut.hir_id);
257256
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
@@ -267,7 +266,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
267266
let pattern = patcx.lower_pattern(pat);
268267
let pattern_ty = pattern.ty;
269268
let pattern = expand_pattern(cx, pattern);
270-
let pats: Matrix<'_, '_> = vec![smallvec![&pattern]].into_iter().collect();
269+
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(&pattern)].into_iter().collect();
271270

272271
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
273272
Ok(_) => return,
@@ -411,7 +410,7 @@ fn check_arms<'tcx>(
411410
let mut catchall = None;
412411
for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
413412
for &(pat, hir_pat) in pats {
414-
let v = smallvec![pat];
413+
let v = PatStack::from_pattern(pat);
415414

416415
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
417416
NotUseful => {
@@ -493,7 +492,7 @@ fn check_not_useful(
493492
hir_id: HirId,
494493
) -> Result<(), Vec<super::Pat<'tcx>>> {
495494
let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
496-
match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness, hir_id) {
495+
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
497496
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
498497
UsefulWithWitness(pats) => Err(if pats.is_empty() {
499498
vec![wild_pattern]

0 commit comments

Comments
 (0)