Skip to content

Commit a66dcd5

Browse files
committed
Simplify slice subtraction as suggested by arielb1
#65160 (comment)
1 parent 087adfe commit a66dcd5

File tree

1 file changed

+40
-62
lines changed

1 file changed

+40
-62
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 40 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ use self::Constructor::*;
225225
use self::Usefulness::*;
226226
use self::WitnessPreference::*;
227227

228+
use rustc_data_structures::fx::FxHashSet;
228229
use rustc_index::vec::Idx;
229230

230231
use super::{compare_const_vals, PatternFoldable, PatternFolder};
@@ -942,25 +943,22 @@ impl<'tcx> Constructor<'tcx> {
942943
// [0] => {}
943944
// [_, _, _] => {}
944945
// [1, 2, 3, 4, 5, 6, ..] => {}
945-
// [_, _, _, _, _, _, _, _] => {}
946+
// [_, _, _, _, _, _, _] => {}
946947
// [0, ..] => {}
947948
// }
948949
// ```
949950
// We want to know which constructors are matched by the last pattern, but are not
950951
// matched by the first four ones. Since we only speak of constructors here, we
951-
// only care about the length of the slices and not the subpatterns.
952+
// only care about the length of the slices and not the particular subpatterns.
952953
// For that, we first notice that because of the third pattern, all constructors of
953954
// lengths 6 or more are covered already. `max_len` will be `Some(6)`.
954-
// Then we'll look at constructors of lengths < 6 to see which are missing. We can
955-
// ignore pattern 4 because it's longer than 6. We are left with patterns 1 and 2.
956-
// The `length` vector will therefore contain `[Start, Boundary(1), Boundary(3),
957-
// Boundary(6)]`.
958-
// The resulting list of remaining constructors will be those strictly between
959-
// those boundaries. Knowing that `self_len` is 1, we get `[FixedLenSlice(2),
960-
// FixedLenSlice(4), FixedLenSlice(5)]`.
961-
// Notice that `FixedLenSlice(0)` is not covered by any of the patterns here, but
962-
// we don't care because we only want constructors that _are_ matched by the last
963-
// pattern.
955+
// Then we'll look at fixed-length constructors to see which are missing. The
956+
// returned list of constructors will be those of lengths in 1..6 that are not
957+
// present in the match. Lengths 1, 3 and 7 are matched already, so we get
958+
// `[FixedLenSlice(2), FixedLenSlice(4), FixedLenSlice(5)]`.
959+
// If we had removed the third pattern, we would have instead returned
960+
// `[FixedLenSlice(2), FixedLenSlice(4), FixedLenSlice(5), FixedLenSlice(6),
961+
// VarLenSlice(8, 0)]`.
964962

965963
// Initially we cover all slice lengths starting from self_len.
966964
let self_len = self_prefix + self_suffix;
@@ -975,70 +973,50 @@ impl<'tcx> Constructor<'tcx> {
975973
})
976974
.min();
977975

976+
// The remaining range of lengths is now either `self_len..`
977+
// or `self_len..max_len`. We then remove from that range all the
978+
// individual FixedLenSlice lengths in used_ctors.
979+
978980
// If max_len <= self_len there are no lengths remaining.
979981
if let Some(max_len) = max_len {
980982
if max_len <= self_len {
981983
return smallvec![];
982984
}
983985
}
984986

985-
// The remaining range of lengths is now either `self_len..`
986-
// or `self_len..max_len`. We then remove from that range all the
987-
// individual FixedLenSlice lengths in used_ctors. For that,
988-
// we extract all those lengths that are in our remaining range and
989-
// sort them. Every such length becomes a boundary between ranges
990-
// of the lengths that will remain.
991-
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
992-
enum Length {
993-
Start, // `Start` will be sorted before `Boundary`
994-
Boundary(u64),
995-
}
996-
use Length::*;
997-
998-
let mut lengths: Vec<_> = used_ctors
987+
// Extract fixed-size lengths
988+
let used_fixed_lengths: FxHashSet<u64> = used_ctors
999989
.iter()
1000-
// Extract fixed-size lengths
1001990
.filter_map(|c: &Constructor<'tcx>| match c {
1002-
FixedLenSlice(other_len) => Some(*other_len),
991+
FixedLenSlice(len) => Some(*len),
1003992
_ => None,
1004993
})
1005-
// Keep only those in the remaining range
1006-
.filter(|l| *l >= self_len)
1007-
.filter(|l| match max_len {
1008-
Some(max_len) => *l < max_len,
1009-
None => true,
1010-
})
1011-
.chain(max_len) // Add max_len as the final boundary
1012-
.map(Boundary)
1013-
.chain(Some(Start)) // Add a special starting boundary
1014-
.collect();
1015-
lengths.sort_unstable();
1016-
lengths.dedup();
1017-
1018-
// For each adjacent pair of lengths, output the lengths in between.
1019-
let mut remaining_ctors: SmallVec<_> = lengths
1020-
.windows(2)
1021-
.flat_map(|window| match (window[0], window[1]) {
1022-
(Boundary(n), Boundary(m)) => (n + 1..m),
1023-
(Start, Boundary(m)) => (self_len..m),
1024-
_ => bug!(),
1025-
})
1026-
.map(FixedLenSlice)
1027994
.collect();
1028995

1029-
// If there was a max_len, then we're done. Otherwise, we
1030-
// still need to include all lengths starting from the longest
1031-
// one until infinity, using VarLenSlice.
1032-
if max_len.is_none() {
1033-
let final_length = match lengths.last().unwrap() {
1034-
Start => self_len,
1035-
Boundary(n) => n + 1,
1036-
};
1037-
// We know final_length >= self_len >= self_suffix so this can't underflow.
1038-
remaining_ctors.push(VarLenSlice(final_length - self_suffix, self_suffix));
996+
if let Some(max_len) = max_len {
997+
(self_len..max_len)
998+
.filter(|len| !used_fixed_lengths.contains(len))
999+
.map(FixedLenSlice)
1000+
.collect()
1001+
} else {
1002+
// Choose a length for which we know that all larger lengths remain in the
1003+
// output.
1004+
let min_free_length = used_fixed_lengths
1005+
.iter()
1006+
.map(|len| len + 1)
1007+
.chain(Some(self_len))
1008+
.max()
1009+
.unwrap();
1010+
1011+
// We know min_free_length >= self_len >= self_suffix so this can't underflow.
1012+
let final_varlen = VarLenSlice(min_free_length - self_suffix, self_suffix);
1013+
1014+
(self_len..min_free_length)
1015+
.filter(|len| !used_fixed_lengths.contains(len))
1016+
.map(FixedLenSlice)
1017+
.chain(Some(final_varlen))
1018+
.collect()
10391019
}
1040-
1041-
remaining_ctors
10421020
}
10431021
IntRange(range) => {
10441022
let used_ranges = used_ctors.iter().flat_map(IntRange::from_ctor);

0 commit comments

Comments
 (0)