Skip to content

Commit c6d1cad

Browse files
committed
Inline max_slice_length
Note that where we previously ran `max_slice_len` with input having not only matrix_head_ctors but also all of v_constructors. Now we run it on matrix_head_ctors and one constructor of v_constructors at a time. In the presence of or-patterns, those two things might differ. However the new behaviour is still valid with regards to the specified semantics of split_meta_constructor.
1 parent 47ee628 commit c6d1cad

File tree

1 file changed

+95
-102
lines changed

1 file changed

+95
-102
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 95 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ impl<'tcx> Constructor<'tcx> {
640640
debug!("split_meta_constructor {:?}", self);
641641
assert!(!head_ctors.iter().any(|c| c.is_wildcard()));
642642

643-
match &self {
643+
match self {
644644
// Any base constructor can be used unchanged.
645645
Single | Variant(_) | ConstantValue(_) | FixedLenSlice(_) => smallvec![self],
646646
ConstantRange(..) if should_treat_range_exhaustively(cx.tcx, &self) => {
@@ -739,8 +739,99 @@ impl<'tcx> Constructor<'tcx> {
739739
.collect()
740740
}
741741
ConstantRange(..) => smallvec![self],
742-
VarLenSlice(prefix, suffix) => {
743-
(prefix + suffix..pcx.max_slice_length + 1).map(FixedLenSlice).collect()
742+
VarLenSlice(self_prefix, self_suffix) => {
743+
// A variable-length slice pattern is matched by an infinite collection of
744+
// fixed-length array patterns. However it turns out that for each finite set of
745+
// patterns `P`, all sufficiently large array lengths are equivalent.
746+
//
747+
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
748+
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
749+
// `sₘ` for each sufficiently-large length `m` that applies to exactly
750+
// the same subset of `P`.
751+
//
752+
// Because of that, each witness for reachability-checking from one of the
753+
// sufficiently-large lengths can be transformed to an equally-valid witness from
754+
// any other length, so we all slice lengths from the "minimal sufficiently-large
755+
// length" until infinity will behave the same.
756+
//
757+
// Note that the fact that there is a *single* `sₘ` for each `m`,
758+
// not depending on the specific pattern in `P`, is important: if
759+
// you look at the pair of patterns
760+
// `[true, ..]`
761+
// `[.., false]`
762+
// Then any slice of length ≥1 that matches one of these two
763+
// patterns can be trivially turned to a slice of any
764+
// other length ≥1 that matches them and vice-versa -
765+
// but the slice from length 2 `[false, true]` that matches neither
766+
// of these patterns can't be turned to a slice from length 1 that
767+
// matches neither of these patterns, so we have to consider
768+
// slices from length 2 there.
769+
//
770+
// Now, to see that that length exists and find it, observe that slice
771+
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
772+
// "variable-length" patterns (`[_, .., _]`).
773+
//
774+
// For fixed-length patterns, all slices with lengths *longer* than
775+
// the pattern's length have the same outcome (of not matching), so
776+
// as long as `L` is greater than the pattern's length we can pick
777+
// any `sₘ` from that length and get the same result.
778+
//
779+
// For variable-length patterns, the situation is more complicated,
780+
// because as seen above the precise value of `sₘ` matters.
781+
//
782+
// However, for each variable-length pattern `p` with a prefix of length
783+
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
784+
// `slₚ` elements are examined.
785+
//
786+
// Therefore, as long as `L` is positive (to avoid concerns about empty
787+
// types), all elements after the maximum prefix length and before
788+
// the maximum suffix length are not examined by any variable-length
789+
// pattern, and therefore can be added/removed without affecting
790+
// them - creating equivalent patterns from any sufficiently-large
791+
// length.
792+
//
793+
// Of course, if fixed-length patterns exist, we must be sure
794+
// that our length is large enough to miss them all, so
795+
// we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
796+
//
797+
// For example, with the above pair of patterns, all elements
798+
// but the first and last can be added/removed, so any
799+
// witness of length ≥2 (say, `[false, false, true]`) can be
800+
// turned to a witness from any other length ≥2.
801+
802+
let mut max_prefix_len = self_prefix;
803+
let mut max_suffix_len = self_suffix;
804+
let mut max_fixed_len = 0;
805+
806+
for ctor in head_ctors {
807+
match *ctor {
808+
ConstantValue(value) => {
809+
// extract the length of an array/slice from a constant
810+
match (value.val, &value.ty.kind) {
811+
(_, ty::Array(_, n)) => {
812+
max_fixed_len =
813+
cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env))
814+
}
815+
(ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
816+
max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
817+
}
818+
_ => {}
819+
}
820+
}
821+
FixedLenSlice(len) => {
822+
max_fixed_len = cmp::max(max_fixed_len, len);
823+
}
824+
VarLenSlice(prefix, suffix) => {
825+
max_prefix_len = cmp::max(max_prefix_len, prefix);
826+
max_suffix_len = cmp::max(max_suffix_len, suffix);
827+
}
828+
_ => {}
829+
}
830+
}
831+
832+
let max_slice_length = cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len);
833+
834+
(self_prefix + self_suffix..=max_slice_length).map(FixedLenSlice).collect()
744835
}
745836
Wildcard => {
746837
let is_declared_nonexhaustive =
@@ -1204,7 +1295,6 @@ pub enum WitnessPreference {
12041295
#[derive(Copy, Clone, Debug)]
12051296
struct PatCtxt<'tcx> {
12061297
ty: Ty<'tcx>,
1207-
max_slice_length: u64,
12081298
}
12091299

12101300
/// A witness of non-exhaustiveness for error reporting, represented
@@ -1364,102 +1454,6 @@ fn all_constructors<'a, 'tcx>(
13641454
ctors
13651455
}
13661456

1367-
fn max_slice_length<'p, 'a, 'tcx, I>(cx: &MatchCheckCtxt<'a, 'tcx>, ctors: I) -> u64
1368-
where
1369-
I: Iterator<Item = &'p Constructor<'tcx>>,
1370-
'tcx: 'p,
1371-
{
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.
1375-
//
1376-
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
1377-
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
1378-
// `sₘ` for each sufficiently-large length `m` that applies to exactly
1379-
// the same subset of `P`.
1380-
//
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.
1385-
//
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
1388-
// you look at the pair of patterns
1389-
// `[true, ..]`
1390-
// `[.., false]`
1391-
// Then any slice of length ≥1 that matches one of these two
1392-
// patterns can be trivially turned to a slice of any
1393-
// other length ≥1 that matches them and vice-versa -
1394-
// but the slice from length 2 `[false, true]` that matches neither
1395-
// of these patterns can't be turned to a slice from length 1 that
1396-
// matches neither of these patterns, so we have to consider
1397-
// slices from length 2 there.
1398-
//
1399-
// Now, to see that that length exists and find it, observe that slice
1400-
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
1401-
// "variable-length" patterns (`[_, .., _]`).
1402-
//
1403-
// For fixed-length patterns, all slices with lengths *longer* than
1404-
// the pattern's length have the same outcome (of not matching), so
1405-
// as long as `L` is greater than the pattern's length we can pick
1406-
// any `sₘ` from that length and get the same result.
1407-
//
1408-
// For variable-length patterns, the situation is more complicated,
1409-
// because as seen above the precise value of `sₘ` matters.
1410-
//
1411-
// However, for each variable-length pattern `p` with a prefix of length
1412-
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
1413-
// `slₚ` elements are examined.
1414-
//
1415-
// Therefore, as long as `L` is positive (to avoid concerns about empty
1416-
// types), all elements after the maximum prefix length and before
1417-
// the maximum suffix length are not examined by any variable-length
1418-
// pattern, and therefore can be added/removed without affecting
1419-
// them - creating equivalent patterns from any sufficiently-large
1420-
// length.
1421-
//
1422-
// Of course, if fixed-length patterns exist, we must be sure
1423-
// that our length is large enough to miss them all, so
1424-
// we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
1425-
//
1426-
// for example, with the above pair of patterns, all elements
1427-
// but the first and last can be added/removed, so any
1428-
// witness of length ≥2 (say, `[false, false, true]`) can be
1429-
// turned to a witness from any other length ≥2.
1430-
1431-
let mut max_prefix_len = 0;
1432-
let mut max_suffix_len = 0;
1433-
let mut max_fixed_len = 0;
1434-
1435-
for ctor in ctors {
1436-
match *ctor {
1437-
ConstantValue(value) => {
1438-
// extract the length of an array/slice from a constant
1439-
match (value.val, &value.ty.kind) {
1440-
(_, ty::Array(_, n)) => {
1441-
max_fixed_len = cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env))
1442-
}
1443-
(ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
1444-
max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
1445-
}
1446-
_ => {}
1447-
}
1448-
}
1449-
FixedLenSlice(len) => {
1450-
max_fixed_len = cmp::max(max_fixed_len, len);
1451-
}
1452-
VarLenSlice(prefix, suffix) => {
1453-
max_prefix_len = cmp::max(max_prefix_len, prefix);
1454-
max_suffix_len = cmp::max(max_suffix_len, suffix);
1455-
}
1456-
_ => {}
1457-
}
1458-
}
1459-
1460-
cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
1461-
}
1462-
14631457
/// An inclusive interval, used for precise integer exhaustiveness checking.
14641458
/// `IntRange`s always store a contiguous range. This means that values are
14651459
/// encoded such that `0` encodes the minimum value for the integer,
@@ -1796,8 +1790,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
17961790
.collect();
17971791
debug!("matrix_head_ctors = {:#?}", matrix_head_ctors);
17981792

1799-
let max_slice_length = max_slice_length(cx, matrix_head_ctors.iter().chain(&v_constructors));
1800-
let pcx = PatCtxt { ty, max_slice_length };
1793+
let pcx = PatCtxt { ty };
18011794

18021795
v_constructors
18031796
.into_iter()

0 commit comments

Comments
 (0)