Skip to content

Commit f9115b1

Browse files
committed
Eagerly simplify match pairs
1 parent 31177a2 commit f9115b1

File tree

4 files changed

+61
-102
lines changed

4 files changed

+61
-102
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -947,12 +947,16 @@ struct Candidate<'pat, 'tcx> {
947947
has_guard: bool,
948948

949949
/// All of these must be satisfied...
950+
// Invariant: all the `MatchPair`s are recursively simplified.
951+
// Invariant: or-patterns must be sorted at the end.
950952
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
951953

952954
/// ...these bindings established...
955+
// Invariant: not mutated outside `Candidate::new()`.
953956
bindings: Vec<Binding<'tcx>>,
954957

955958
/// ...and these types asserted...
959+
// Invariant: not mutated outside `Candidate::new()`.
956960
ascriptions: Vec<Ascription<'tcx>>,
957961

958962
/// ...and if this is non-empty, one of these subcandidates also has to match...
@@ -972,9 +976,9 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
972976
place: PlaceBuilder<'tcx>,
973977
pattern: &'pat Pat<'tcx>,
974978
has_guard: bool,
975-
cx: &Builder<'_, 'tcx>,
979+
cx: &mut Builder<'_, 'tcx>,
976980
) -> Self {
977-
Candidate {
981+
let mut candidate = Candidate {
978982
span: pattern.span,
979983
has_guard,
980984
match_pairs: vec![MatchPair::new(place, pattern, cx)],
@@ -984,7 +988,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
984988
otherwise_block: None,
985989
pre_binding_block: None,
986990
next_candidate_pre_binding_block: None,
987-
}
991+
};
992+
993+
cx.simplify_match_pairs(
994+
&mut candidate.match_pairs,
995+
&mut candidate.bindings,
996+
&mut candidate.ascriptions,
997+
);
998+
999+
candidate
9881000
}
9891001

9901002
/// Visit the leaf candidates (those with no subcandidates) contained in
@@ -1040,13 +1052,18 @@ struct Ascription<'tcx> {
10401052
variance: ty::Variance,
10411053
}
10421054

1043-
#[derive(Clone, Debug)]
1055+
#[derive(Debug)]
10441056
pub(crate) struct MatchPair<'pat, 'tcx> {
1045-
// this place...
1057+
// This place...
10461058
place: PlaceBuilder<'tcx>,
10471059

10481060
// ... must match this pattern.
1061+
// Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be
1062+
// simplified, i.e. require a test.
10491063
pattern: &'pat Pat<'tcx>,
1064+
1065+
/// Precomputed sub-match pairs of `pattern`.
1066+
subpairs: Vec<Self>,
10501067
}
10511068

10521069
/// See [`Test`] for more.
@@ -1163,16 +1180,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11631180
candidates: &mut [&mut Candidate<'pat, 'tcx>],
11641181
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
11651182
) {
1166-
// Start by simplifying candidates. Once this process is complete, all
1167-
// the match pairs which remain require some form of test, whether it
1168-
// be a switch or pattern comparison.
11691183
let mut split_or_candidate = false;
11701184
for candidate in &mut *candidates {
1171-
self.simplify_match_pairs(
1172-
&mut candidate.match_pairs,
1173-
&mut candidate.bindings,
1174-
&mut candidate.ascriptions,
1175-
);
11761185
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
11771186
&*candidate.match_pairs
11781187
{

compiler/rustc_mir_build/src/build/matches/simplify.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
107107
pats.iter()
108108
.map(|box pat| {
109109
let mut candidate = Candidate::new(place.clone(), pat, has_guard, self);
110-
self.simplify_match_pairs(
111-
&mut candidate.match_pairs,
112-
&mut candidate.bindings,
113-
&mut candidate.ascriptions,
114-
);
115-
116110
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
117111
&*candidate.match_pairs
118112
{
@@ -132,11 +126,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
132126
/// candidate.
133127
fn simplify_match_pair<'pat>(
134128
&mut self,
135-
match_pair: MatchPair<'pat, 'tcx>,
129+
mut match_pair: MatchPair<'pat, 'tcx>,
136130
bindings: &mut Vec<Binding<'tcx>>,
137131
ascriptions: &mut Vec<Ascription<'tcx>>,
138132
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
139133
) -> Result<(), MatchPair<'pat, 'tcx>> {
134+
assert!(match_pair.subpairs.is_empty(), "mustn't simplify a match pair twice");
140135
match match_pair.pattern.kind {
141136
PatKind::AscribeUserType {
142137
ref subpattern,
@@ -249,6 +244,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
249244
self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix);
250245
Ok(())
251246
} else {
247+
self.prefix_slice_suffix(
248+
&mut match_pair.subpairs,
249+
&match_pair.place,
250+
prefix,
251+
slice,
252+
suffix,
253+
);
254+
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
252255
Err(match_pair)
253256
}
254257
}
@@ -270,6 +273,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
270273
match_pairs.extend(self.field_match_pairs(place_builder, subpatterns));
271274
Ok(())
272275
} else {
276+
let downcast_place = match_pair.place.clone().downcast(adt_def, variant_index); // `(x as Variant)`
277+
match_pair.subpairs = self.field_match_pairs(downcast_place, subpatterns);
278+
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
273279
Err(match_pair)
274280
}
275281
}

compiler/rustc_mir_build/src/build/matches/test.rs

+25-81
Original file line numberDiff line numberDiff line change
@@ -589,22 +589,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
589589
// away.)
590590
let (match_pair_index, match_pair) =
591591
candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
592+
let mut fully_matched = false;
592593

593-
match (&test.kind, &match_pair.pattern.kind) {
594+
let ret = match (&test.kind, &match_pair.pattern.kind) {
594595
// If we are performing a variant switch, then this
595596
// informs variant patterns, but nothing else.
596597
(
597598
&TestKind::Switch { adt_def: tested_adt_def, .. },
598-
&PatKind::Variant { adt_def, variant_index, ref subpatterns, .. },
599+
&PatKind::Variant { adt_def, variant_index, .. },
599600
) => {
600601
assert_eq!(adt_def, tested_adt_def);
601-
self.candidate_after_variant_switch(
602-
match_pair_index,
603-
adt_def,
604-
variant_index,
605-
subpatterns,
606-
candidate,
607-
);
602+
fully_matched = true;
608603
Some(variant_index.as_usize())
609604
}
610605

@@ -618,8 +613,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
618613
(TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
619614
if is_switch_ty(match_pair.pattern.ty) =>
620615
{
616+
fully_matched = true;
621617
let index = options.get_index_of(value).unwrap();
622-
self.candidate_without_match_pair(match_pair_index, candidate);
623618
Some(index)
624619
}
625620

@@ -645,13 +640,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
645640
(Ordering::Equal, &None) => {
646641
// on true, min_len = len = $actual_length,
647642
// on false, len != $actual_length
648-
self.candidate_after_slice_test(
649-
match_pair_index,
650-
candidate,
651-
prefix,
652-
slice,
653-
suffix,
654-
);
643+
fully_matched = true;
655644
Some(0)
656645
}
657646
(Ordering::Less, _) => {
@@ -683,13 +672,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
683672
(Ordering::Equal, &Some(_)) => {
684673
// $actual_len >= test_len = pat_len,
685674
// so we can match.
686-
self.candidate_after_slice_test(
687-
match_pair_index,
688-
candidate,
689-
prefix,
690-
slice,
691-
suffix,
692-
);
675+
fully_matched = true;
693676
Some(0)
694677
}
695678
(Ordering::Less, _) | (Ordering::Equal, &None) => {
@@ -713,13 +696,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
713696

714697
(TestKind::Range(test), PatKind::Range(pat)) => {
715698
if test == pat {
716-
self.candidate_without_match_pair(match_pair_index, candidate);
717-
return Some(0);
699+
fully_matched = true;
700+
Some(0)
701+
} else {
702+
// If the testing range does not overlap with pattern range,
703+
// the pattern can be matched only if this test fails.
704+
if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
718705
}
719-
720-
// If the testing range does not overlap with pattern range,
721-
// the pattern can be matched only if this test fails.
722-
if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
723706
}
724707

725708
(TestKind::Range(range), &PatKind::Constant { value }) => {
@@ -751,64 +734,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
751734
// FIXME(#29623) we can be more clever here
752735
let pattern_test = self.test(match_pair);
753736
if pattern_test.kind == test.kind {
754-
self.candidate_without_match_pair(match_pair_index, candidate);
737+
fully_matched = true;
755738
Some(0)
756739
} else {
757740
None
758741
}
759742
}
760-
}
761-
}
762-
763-
fn candidate_without_match_pair(
764-
&mut self,
765-
match_pair_index: usize,
766-
candidate: &mut Candidate<'_, 'tcx>,
767-
) {
768-
candidate.match_pairs.remove(match_pair_index);
769-
}
743+
};
770744

771-
fn candidate_after_slice_test<'pat>(
772-
&mut self,
773-
match_pair_index: usize,
774-
candidate: &mut Candidate<'pat, 'tcx>,
775-
prefix: &'pat [Box<Pat<'tcx>>],
776-
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
777-
suffix: &'pat [Box<Pat<'tcx>>],
778-
) {
779-
let removed_place = candidate.match_pairs.remove(match_pair_index).place;
780-
self.prefix_slice_suffix(
781-
&mut candidate.match_pairs,
782-
&removed_place,
783-
prefix,
784-
opt_slice,
785-
suffix,
786-
);
787-
}
745+
if fully_matched {
746+
// Replace the match pair by its sub-pairs.
747+
let match_pair = candidate.match_pairs.remove(match_pair_index);
748+
candidate.match_pairs.extend(match_pair.subpairs);
749+
// Move or-patterns to the end.
750+
candidate
751+
.match_pairs
752+
.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
753+
}
788754

789-
fn candidate_after_variant_switch<'pat>(
790-
&mut self,
791-
match_pair_index: usize,
792-
adt_def: ty::AdtDef<'tcx>,
793-
variant_index: VariantIdx,
794-
subpatterns: &'pat [FieldPat<'tcx>],
795-
candidate: &mut Candidate<'pat, 'tcx>,
796-
) {
797-
let match_pair = candidate.match_pairs.remove(match_pair_index);
798-
799-
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
800-
// we want to create a set of derived match-patterns like
801-
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
802-
let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
803-
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
804-
// e.g., `(x as Variant).0`
805-
let place = downcast_place
806-
.clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
807-
// e.g., `(x as Variant).0 @ P1`
808-
MatchPair::new(place, &subpattern.pattern, self)
809-
});
810-
811-
candidate.match_pairs.extend(consequent_match_pairs);
755+
ret
812756
}
813757

814758
fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {

compiler/rustc_mir_build/src/build/matches/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
116116
if may_need_cast {
117117
place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
118118
}
119-
MatchPair { place, pattern }
119+
MatchPair { place, pattern, subpairs: Vec::new() }
120120
}
121121
}

0 commit comments

Comments
 (0)