Skip to content

Commit ed3ea67

Browse files
committed
Restore performance
Stop checking that cached constructors are valid. Avoid cloning constructors when not necessary.
1 parent 6df1815 commit ed3ea67

File tree

1 file changed

+27
-24
lines changed

1 file changed

+27
-24
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,15 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> {
334334
}
335335
}
336336

337-
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
338-
/// works well.
337+
/// A row of a matrix.
339338
#[derive(Debug, Clone)]
340339
pub struct PatStack<'p, 'tcx> {
340+
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
341341
patterns: SmallVec<[&'p Pat<'tcx>; 2]>,
342342
// This caches the invocation of `pat_constructors` on the head of the stack. We avoid mutating
343343
// `self` to be sure we don't keep an invalid cache around. Must be non-empty unless `patterns`
344344
// is empty.
345-
head_ctors_cache: SmallVec<[Constructor<'tcx>; 1]>,
345+
head_ctors: SmallVec<[Constructor<'tcx>; 1]>,
346346
}
347347

348348
impl<'p, 'tcx> PatStack<'p, 'tcx> {
@@ -351,15 +351,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
351351
}
352352

353353
fn empty() -> Self {
354-
PatStack { patterns: smallvec![], head_ctors_cache: smallvec![] }
354+
PatStack { patterns: smallvec![], head_ctors: smallvec![] }
355355
}
356356

357357
fn from_vec(cx: &MatchCheckCtxt<'_, 'tcx>, patterns: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
358358
if patterns.is_empty() {
359359
return PatStack::empty();
360360
}
361-
let head_ctors_cache = pat_constructors(cx.tcx, cx.param_env, patterns[0]);
362-
PatStack { patterns, head_ctors_cache }
361+
let head_ctors = pat_constructors(cx.tcx, cx.param_env, patterns[0]);
362+
PatStack { patterns, head_ctors }
363363
}
364364

365365
fn from_slice(cx: &MatchCheckCtxt<'_, 'tcx>, s: &[&'p Pat<'tcx>]) -> Self {
@@ -378,10 +378,8 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
378378
self.patterns[0]
379379
}
380380

381-
fn head_ctors(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
382-
let new_ctors = pat_constructors(cx.tcx, cx.param_env, self.head());
383-
assert_eq!(self.head_ctors_cache, new_ctors);
384-
new_ctors
381+
fn head_ctors(&self) -> &SmallVec<[Constructor<'tcx>; 1]> {
382+
&self.head_ctors
385383
}
386384

387385
fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
@@ -436,8 +434,8 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
436434
self.0.iter().map(|r| r.head())
437435
}
438436

439-
fn head_ctors(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Vec<Constructor<'tcx>> {
440-
self.0.iter().flat_map(|r| r.head_ctors(cx)).filter(|ctor| !ctor.is_wildcard()).collect()
437+
fn head_ctors(&self) -> Vec<&Constructor<'tcx>> {
438+
self.0.iter().flat_map(|r| r.head_ctors()).filter(|ctor| !ctor.is_wildcard()).collect()
441439
}
442440

443441
/// This computes `S(constructor, self)`. See top of the file for explanations.
@@ -641,18 +639,18 @@ impl<'tcx> Constructor<'tcx> {
641639
/// for the given matrix. See description of the algorithm for details.
642640
/// Note: We can rely on this returning an empty list if the type is (visibly) uninhabited.
643641
fn split_meta_constructor(
644-
self,
642+
&self,
645643
cx: &MatchCheckCtxt<'_, 'tcx>,
646644
ty: Ty<'tcx>,
647-
head_ctors: &Vec<Constructor<'tcx>>,
645+
head_ctors: &Vec<&Constructor<'tcx>>,
648646
) -> SmallVec<[Constructor<'tcx>; 1]> {
649647
debug!("split_meta_constructor {:?}", self);
650648
assert!(!head_ctors.iter().any(|c| c.is_wildcard()));
651649

652-
match self {
650+
match *self {
653651
// Any base constructor can be used unchanged.
654-
Single | Variant(_) | ConstantValue(_) | FixedLenSlice(_) => smallvec![self],
655-
IntRange(ctor_range) if IntRange::should_treat_range_exhaustively(cx.tcx, ty) => {
652+
Single | Variant(_) | ConstantValue(_) | FixedLenSlice(_) => smallvec![self.clone()],
653+
IntRange(ref ctor_range) if IntRange::should_treat_range_exhaustively(cx.tcx, ty) => {
656654
// Splitting up a range naïvely would mean creating a separate constructor for
657655
// every single value in the range, which is clearly impractical. We therefore want
658656
// to keep together subranges for which the specialisation will be identical across
@@ -708,6 +706,7 @@ impl<'tcx> Constructor<'tcx> {
708706
// class lies between 2 borders.
709707
let row_borders = head_ctors
710708
.iter()
709+
.map(|c| *c)
711710
.flat_map(IntRange::from_ctor)
712711
.flat_map(|range| ctor_range.intersection(cx.tcx, &range))
713712
.flat_map(|range| range_borders(range));
@@ -736,7 +735,7 @@ impl<'tcx> Constructor<'tcx> {
736735
.collect()
737736
}
738737
// When not treated exhaustively, don't split ranges.
739-
ConstantRange(..) | IntRange(..) => smallvec![self],
738+
ConstantRange(..) | IntRange(..) => smallvec![self.clone()],
740739
VarLenSlice(self_prefix, self_suffix) => {
741740
// A variable-length slice pattern is matched by an infinite collection of
742741
// fixed-length array patterns. However it turns out that for each finite set of
@@ -806,7 +805,7 @@ impl<'tcx> Constructor<'tcx> {
806805
let mut max_fixed_len = 0;
807806

808807
for ctor in head_ctors {
809-
match *ctor {
808+
match **ctor {
810809
ConstantValue(value) => {
811810
// Extract the length of an array/slice from a constant
812811
match (value.val, &value.ty.kind) {
@@ -868,8 +867,12 @@ impl<'tcx> Constructor<'tcx> {
868867
// Therefore, if there is some pattern that is unmatched by `matrix`,
869868
// it will still be unmatched if the first constructor is replaced by
870869
// any of the constructors in `missing_ctors`
871-
let missing_ctors =
872-
MissingConstructors::new(cx.tcx, cx.param_env, all_ctors, head_ctors.clone());
870+
let missing_ctors = MissingConstructors::new(
871+
cx.tcx,
872+
cx.param_env,
873+
all_ctors,
874+
head_ctors.iter().map(|c| (**c).clone()).collect(),
875+
);
873876
debug!(
874877
"missing_ctors.is_empty()={:#?} is_non_exhaustive={:#?}",
875878
missing_ctors.is_empty(),
@@ -1760,7 +1763,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
17601763

17611764
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", ty, v.head());
17621765

1763-
let v_constructors = v.head_ctors(cx);
1766+
let v_constructors = v.head_ctors();
17641767

17651768
if cx.is_non_exhaustive_variant(v.head())
17661769
&& !cx.is_local(ty)
@@ -1771,11 +1774,11 @@ pub fn is_useful<'p, 'a, 'tcx>(
17711774
return Useful;
17721775
}
17731776

1774-
let matrix_head_ctors = matrix.head_ctors(cx);
1777+
let matrix_head_ctors = matrix.head_ctors();
17751778
debug!("matrix_head_ctors = {:#?}", matrix_head_ctors);
17761779

17771780
v_constructors
1778-
.into_iter()
1781+
.iter()
17791782
.flat_map(|ctor| ctor.split_meta_constructor(cx, ty, &matrix_head_ctors))
17801783
.map(|c| is_useful_specialized(cx, matrix, v, c, ty, witness_preference))
17811784
.find(|result| result.is_useful())

0 commit comments

Comments
 (0)