Skip to content

Commit 47ee628

Browse files
committed
max_slice_length only needs to look at constructors
1 parent ad09cc5 commit 47ee628

File tree

1 file changed

+51
-57
lines changed

1 file changed

+51
-57
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,38 +1364,33 @@ fn all_constructors<'a, 'tcx>(
13641364
ctors
13651365
}
13661366

1367-
fn max_slice_length<'p, 'a, 'tcx, I>(cx: &MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64
1367+
fn max_slice_length<'p, 'a, 'tcx, I>(cx: &MatchCheckCtxt<'a, 'tcx>, ctors: I) -> u64
13681368
where
1369-
I: Iterator<Item = &'p Pat<'tcx>>,
1369+
I: Iterator<Item = &'p Constructor<'tcx>>,
13701370
'tcx: 'p,
13711371
{
1372-
// The exhaustiveness-checking paper does not include any details on
1373-
// checking variable-length slice patterns. However, they are matched
1374-
// by an infinite collection of fixed-length array patterns.
1375-
//
1376-
// Checking the infinite set directly would take an infinite amount
1377-
// of time. However, it turns out that for each finite set of
1378-
// patterns `P`, all sufficiently large array lengths are equivalent:
1372+
// A variable-length slice pattern is matched by an infinite collection of fixed-length array
1373+
// patterns. However it turns out that for each finite set of patterns `P`, all sufficiently
1374+
// large array lengths are equivalent.
13791375
//
13801376
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
13811377
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
13821378
// `sₘ` for each sufficiently-large length `m` that applies to exactly
13831379
// the same subset of `P`.
13841380
//
1385-
// Because of that, each witness for reachability-checking from one
1386-
// of the sufficiently-large lengths can be transformed to an
1387-
// equally-valid witness from any other length, so we only have
1388-
// to check slice lengths from the "minimal sufficiently-large length"
1389-
// and below.
1381+
// Because of that, each witness for reachability-checking from one of the sufficiently-large
1382+
// lengths can be transformed to an equally-valid witness from any other length, so we all
1383+
// slice lengths from the "minimal sufficiently-large length" until infinity will behave the
1384+
// same.
13901385
//
1391-
// Note that the fact that there is a *single* `sₘ` for each `m`
1392-
// not depending on the specific pattern in `P` is important: if
1386+
// Note that the fact that there is a *single* `sₘ` for each `m`,
1387+
// not depending on the specific pattern in `P`, is important: if
13931388
// you look at the pair of patterns
13941389
// `[true, ..]`
13951390
// `[.., false]`
13961391
// Then any slice of length ≥1 that matches one of these two
13971392
// patterns can be trivially turned to a slice of any
1398-
// other length ≥1 that matches them and vice-versa - for
1393+
// other length ≥1 that matches them and vice-versa -
13991394
// but the slice from length 2 `[false, true]` that matches neither
14001395
// of these patterns can't be turned to a slice from length 1 that
14011396
// matches neither of these patterns, so we have to consider
@@ -1437,9 +1432,9 @@ where
14371432
let mut max_suffix_len = 0;
14381433
let mut max_fixed_len = 0;
14391434

1440-
for row in patterns {
1441-
match *row.kind {
1442-
PatKind::Constant { value } => {
1435+
for ctor in ctors {
1436+
match *ctor {
1437+
ConstantValue(value) => {
14431438
// extract the length of an array/slice from a constant
14441439
match (value.val, &value.ty.kind) {
14451440
(_, ty::Array(_, n)) => {
@@ -1451,13 +1446,12 @@ where
14511446
_ => {}
14521447
}
14531448
}
1454-
PatKind::Slice { ref prefix, slice: None, ref suffix } => {
1455-
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
1456-
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
1449+
FixedLenSlice(len) => {
1450+
max_fixed_len = cmp::max(max_fixed_len, len);
14571451
}
1458-
PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
1459-
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
1460-
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
1452+
VarLenSlice(prefix, suffix) => {
1453+
max_prefix_len = cmp::max(max_prefix_len, prefix);
1454+
max_suffix_len = cmp::max(max_suffix_len, suffix);
14611455
}
14621456
_ => {}
14631457
}
@@ -1761,36 +1755,33 @@ pub fn is_useful<'p, 'a, 'tcx>(
17611755

17621756
assert!(rows.iter().all(|r| r.len() == v.len()));
17631757

1764-
let pcx = PatCtxt {
1765-
// TyErr is used to represent the type of wildcard patterns matching
1766-
// against inaccessible (private) fields of structs, so that we won't
1767-
// be able to observe whether the types of the struct's fields are
1768-
// inhabited.
1769-
//
1770-
// If the field is truly inaccessible, then all the patterns
1771-
// matching against it must be wildcard patterns, so its type
1772-
// does not matter.
1773-
//
1774-
// However, if we are matching against non-wildcard patterns, we
1775-
// need to know the real type of the field so we can specialize
1776-
// against it. This primarily occurs through constants - they
1777-
// can include contents for fields that are inaccessible at the
1778-
// location of the match. In that case, the field's type is
1779-
// inhabited - by the constant - so we can just use it.
1780-
//
1781-
// FIXME: this might lead to "unstable" behavior with macro hygiene
1782-
// introducing uninhabited patterns for inaccessible fields. We
1783-
// need to figure out how to model that.
1784-
ty: matrix.heads().map(|p| p.ty).find(|ty| !ty.references_error()).unwrap_or(v.head().ty),
1785-
max_slice_length: max_slice_length(cx, matrix.heads().chain(Some(v.head()))),
1786-
};
1758+
// TyErr is used to represent the type of wildcard patterns matching
1759+
// against inaccessible (private) fields of structs, so that we won't
1760+
// be able to observe whether the types of the struct's fields are
1761+
// inhabited.
1762+
//
1763+
// If the field is truly inaccessible, then all the patterns
1764+
// matching against it must be wildcard patterns, so its type
1765+
// does not matter.
1766+
//
1767+
// However, if we are matching against non-wildcard patterns, we
1768+
// need to know the real type of the field so we can specialize
1769+
// against it. This primarily occurs through constants - they
1770+
// can include contents for fields that are inaccessible at the
1771+
// location of the match. In that case, the field's type is
1772+
// inhabited - by the constant - so we can just use it.
1773+
//
1774+
// FIXME: this might lead to "unstable" behavior with macro hygiene
1775+
// introducing uninhabited patterns for inaccessible fields. We
1776+
// need to figure out how to model that.
1777+
let ty = matrix.heads().map(|p| p.ty).find(|ty| !ty.references_error()).unwrap_or(v.head().ty);
17871778

1788-
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
1779+
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", ty, v.head());
17891780

1790-
let v_constructors = pat_constructors(cx.tcx, cx.param_env, v.head(), pcx);
1781+
let v_constructors = pat_constructors(cx.tcx, cx.param_env, v.head(), ty);
17911782

17921783
if cx.is_non_exhaustive_variant(v.head())
1793-
&& !cx.is_local(pcx.ty)
1784+
&& !cx.is_local(ty)
17941785
&& !v_constructors.iter().any(|ctor| ctor.is_wildcard())
17951786
{
17961787
debug!("is_useful - shortcut because declared non-exhaustive");
@@ -1800,11 +1791,14 @@ pub fn is_useful<'p, 'a, 'tcx>(
18001791

18011792
let matrix_head_ctors: Vec<Constructor<'_>> = matrix
18021793
.heads()
1803-
.flat_map(|p| pat_constructors(cx.tcx, cx.param_env, p, pcx))
1794+
.flat_map(|p| pat_constructors(cx.tcx, cx.param_env, p, ty))
18041795
.filter(|ctor| !ctor.is_wildcard())
18051796
.collect();
18061797
debug!("matrix_head_ctors = {:#?}", matrix_head_ctors);
18071798

1799+
let max_slice_length = max_slice_length(cx, matrix_head_ctors.iter().chain(&v_constructors));
1800+
let pcx = PatCtxt { ty, max_slice_length };
1801+
18081802
v_constructors
18091803
.into_iter()
18101804
.flat_map(|ctor| ctor.split_meta_constructor(cx, pcx, &matrix_head_ctors))
@@ -1851,11 +1845,11 @@ fn pat_constructors<'tcx>(
18511845
tcx: TyCtxt<'tcx>,
18521846
param_env: ty::ParamEnv<'tcx>,
18531847
pat: &Pat<'tcx>,
1854-
pcx: PatCtxt<'tcx>,
1848+
ty: Ty<'tcx>,
18551849
) -> SmallVec<[Constructor<'tcx>; 1]> {
18561850
match *pat.kind {
18571851
PatKind::AscribeUserType { ref subpattern, .. } => {
1858-
pat_constructors(tcx, param_env, subpattern, pcx)
1852+
pat_constructors(tcx, param_env, subpattern, ty)
18591853
}
18601854
PatKind::Binding { .. } | PatKind::Wild => smallvec![Wildcard],
18611855
PatKind::Leaf { .. } | PatKind::Deref { .. } => smallvec![Single],
@@ -1869,9 +1863,9 @@ fn pat_constructors<'tcx>(
18691863
lo.ty,
18701864
end,
18711865
)],
1872-
PatKind::Array { .. } => match pcx.ty.kind {
1866+
PatKind::Array { .. } => match ty.kind {
18731867
ty::Array(_, length) => smallvec![FixedLenSlice(length.eval_usize(tcx, param_env))],
1874-
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty),
1868+
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", ty),
18751869
},
18761870
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
18771871
let prefix = prefix.len() as u64;

0 commit comments

Comments
 (0)