Skip to content

Commit edea739

Browse files
committed
No need to collect test variants ahead of time
1 parent 8c3688c commit edea739

File tree

2 files changed

+38
-147
lines changed

2 files changed

+38
-147
lines changed

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

+11-34
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_data_structures::{
1414
fx::{FxHashSet, FxIndexMap, FxIndexSet},
1515
stack::ensure_sufficient_stack,
1616
};
17-
use rustc_index::bit_set::BitSet;
1817
use rustc_middle::middle::region;
1918
use rustc_middle::mir::{self, *};
2019
use rustc_middle::thir::{self, *};
@@ -1116,19 +1115,10 @@ enum TestKind<'tcx> {
11161115
Switch {
11171116
/// The enum type being tested.
11181117
adt_def: ty::AdtDef<'tcx>,
1119-
/// The set of variants that we should create a branch for. We also
1120-
/// create an additional "otherwise" case.
1121-
variants: BitSet<VariantIdx>,
11221118
},
11231119

11241120
/// Test what value an integer or `char` has.
1125-
SwitchInt {
1126-
/// The (ordered) set of values that we test for.
1127-
///
1128-
/// We create a branch to each of the values in `options`, as well as an "otherwise" branch
1129-
/// for all other values, even in the (rare) case that `options` is exhaustive.
1130-
options: FxIndexMap<Const<'tcx>, u128>,
1131-
},
1121+
SwitchInt,
11321122

11331123
/// Test what value a `bool` has.
11341124
If,
@@ -1173,6 +1163,12 @@ enum TestBranch<'tcx> {
11731163
Failure,
11741164
}
11751165

1166+
impl<'tcx> TestBranch<'tcx> {
1167+
fn as_constant(&self) -> Option<&Const<'tcx>> {
1168+
if let Self::Constant(v, _) = self { Some(v) } else { None }
1169+
}
1170+
}
1171+
11761172
/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether
11771173
/// a match arm has a guard expression attached to it.
11781174
#[derive(Copy, Clone, Debug)]
@@ -1583,30 +1579,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15831579
) -> (PlaceBuilder<'tcx>, Test<'tcx>) {
15841580
// Extract the match-pair from the highest priority candidate
15851581
let match_pair = &candidates.first().unwrap().match_pairs[0];
1586-
let mut test = self.test(match_pair);
1582+
let test = self.test(match_pair);
15871583
let match_place = match_pair.place.clone();
1588-
15891584
debug!(?test, ?match_pair);
1590-
// Most of the time, the test to perform is simply a function of the main candidate; but for
1591-
// a test like SwitchInt, we may want to add cases based on the candidates that are
1592-
// available
1593-
match test.kind {
1594-
TestKind::SwitchInt { ref mut options } => {
1595-
for candidate in candidates.iter() {
1596-
if !self.add_cases_to_switch(&match_place, candidate, options) {
1597-
break;
1598-
}
1599-
}
1600-
}
1601-
TestKind::Switch { adt_def: _, ref mut variants } => {
1602-
for candidate in candidates.iter() {
1603-
if !self.add_variants_to_switch(&match_place, candidate, variants) {
1604-
break;
1605-
}
1606-
}
1607-
}
1608-
_ => {}
1609-
}
16101585

16111586
(match_place, test)
16121587
}
@@ -1663,7 +1638,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16631638
// point we may encounter a candidate where the test is not relevant; at that point, we stop
16641639
// sorting.
16651640
while let Some(candidate) = candidates.first_mut() {
1666-
let Some(branch) = self.sort_candidate(&match_place, &test, candidate) else {
1641+
let Some(branch) =
1642+
self.sort_candidate(&match_place, test, candidate, &target_candidates)
1643+
else {
16671644
break;
16681645
};
16691646
let (candidate, rest) = candidates.split_first_mut().unwrap();

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

+27-113
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,14 @@ use crate::build::matches::{Candidate, MatchPair, Test, TestBranch, TestCase, Te
1010
use crate::build::Builder;
1111
use rustc_data_structures::fx::FxIndexMap;
1212
use rustc_hir::{LangItem, RangeEnd};
13-
use rustc_index::bit_set::BitSet;
1413
use rustc_middle::mir::*;
15-
use rustc_middle::thir::*;
1614
use rustc_middle::ty::util::IntTypeExt;
1715
use rustc_middle::ty::GenericArg;
1816
use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
1917
use rustc_span::def_id::DefId;
2018
use rustc_span::source_map::Spanned;
2119
use rustc_span::symbol::{sym, Symbol};
2220
use rustc_span::{Span, DUMMY_SP};
23-
use rustc_target::abi::VariantIdx;
2421

2522
use std::cmp::Ordering;
2623

@@ -30,22 +27,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3027
/// It is a bug to call this with a not-fully-simplified pattern.
3128
pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
3229
let kind = match match_pair.test_case {
33-
TestCase::Variant { adt_def, variant_index: _ } => {
34-
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
35-
}
30+
TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
3631

3732
TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If,
38-
39-
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
40-
// For integers, we use a `SwitchInt` match, which allows
41-
// us to handle more cases.
42-
TestKind::SwitchInt {
43-
// these maps are empty to start; cases are
44-
// added below in add_cases_to_switch
45-
options: Default::default(),
46-
}
47-
}
48-
33+
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => TestKind::SwitchInt,
4934
TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty },
5035

5136
TestCase::Range(range) => {
@@ -70,57 +55,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7055
Test { span: match_pair.pattern.span, kind }
7156
}
7257

73-
pub(super) fn add_cases_to_switch<'pat>(
74-
&mut self,
75-
test_place: &PlaceBuilder<'tcx>,
76-
candidate: &Candidate<'pat, 'tcx>,
77-
options: &mut FxIndexMap<Const<'tcx>, u128>,
78-
) -> bool {
79-
let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
80-
else {
81-
return false;
82-
};
83-
84-
match match_pair.test_case {
85-
TestCase::Constant { value } => {
86-
options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
87-
true
88-
}
89-
TestCase::Variant { .. } => {
90-
panic!("you should have called add_variants_to_switch instead!");
91-
}
92-
TestCase::Range(ref range) => {
93-
// Check that none of the switch values are in the range.
94-
self.values_not_contained_in_range(&*range, options).unwrap_or(false)
95-
}
96-
// don't know how to add these patterns to a switch
97-
_ => false,
98-
}
99-
}
100-
101-
pub(super) fn add_variants_to_switch<'pat>(
102-
&mut self,
103-
test_place: &PlaceBuilder<'tcx>,
104-
candidate: &Candidate<'pat, 'tcx>,
105-
variants: &mut BitSet<VariantIdx>,
106-
) -> bool {
107-
let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
108-
else {
109-
return false;
110-
};
111-
112-
match match_pair.test_case {
113-
TestCase::Variant { variant_index, .. } => {
114-
// We have a pattern testing for variant `variant_index`
115-
// set the corresponding index to true
116-
variants.insert(variant_index);
117-
true
118-
}
119-
// don't know how to add these patterns to a switch
120-
_ => false,
121-
}
122-
}
123-
12458
#[instrument(skip(self, target_blocks, place_builder), level = "debug")]
12559
pub(super) fn perform_test(
12660
&mut self,
@@ -139,33 +73,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13973

14074
let source_info = self.source_info(test.span);
14175
match test.kind {
142-
TestKind::Switch { adt_def, ref variants } => {
143-
// Variants is a BitVec of indexes into adt_def.variants.
144-
let num_enum_variants = adt_def.variants().len();
76+
TestKind::Switch { adt_def } => {
14577
let otherwise_block = target_block(TestBranch::Failure);
146-
let tcx = self.tcx;
14778
let switch_targets = SwitchTargets::new(
148-
adt_def.discriminants(tcx).filter_map(|(idx, discr)| {
149-
if variants.contains(idx) {
150-
debug_assert_ne!(
151-
target_block(TestBranch::Variant(idx)),
152-
otherwise_block,
153-
"no candidates for tested discriminant: {discr:?}",
154-
);
155-
Some((discr.val, target_block(TestBranch::Variant(idx))))
79+
adt_def.discriminants(self.tcx).filter_map(|(idx, discr)| {
80+
if let Some(&block) = target_blocks.get(&TestBranch::Variant(idx)) {
81+
Some((discr.val, block))
15682
} else {
157-
debug_assert_eq!(
158-
target_block(TestBranch::Variant(idx)),
159-
otherwise_block,
160-
"found candidates for untested discriminant: {discr:?}",
161-
);
16283
None
16384
}
16485
}),
16586
otherwise_block,
16687
);
167-
debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
168-
let discr_ty = adt_def.repr().discr_type().to_ty(tcx);
88+
debug!("num_enum_variants: {}", adt_def.variants().len());
89+
let discr_ty = adt_def.repr().discr_type().to_ty(self.tcx);
16990
let discr = self.temp(discr_ty, test.span);
17091
self.cfg.push_assign(
17192
block,
@@ -183,13 +104,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183104
);
184105
}
185106

186-
TestKind::SwitchInt { ref options } => {
107+
TestKind::SwitchInt => {
187108
// The switch may be inexhaustive so we have a catch-all block
188109
let otherwise_block = target_block(TestBranch::Failure);
189110
let switch_targets = SwitchTargets::new(
190-
options
191-
.iter()
192-
.map(|(&val, &bits)| (bits, target_block(TestBranch::Constant(val, bits)))),
111+
target_blocks.iter().filter_map(|(&branch, &block)| {
112+
if let TestBranch::Constant(_, bits) = branch {
113+
Some((bits, block))
114+
} else {
115+
None
116+
}
117+
}),
193118
otherwise_block,
194119
);
195120
let terminator = TerminatorKind::SwitchInt {
@@ -548,11 +473,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
548473
/// that it *doesn't* apply. For now, we return false, indicate that the
549474
/// test does not apply to this candidate, but it might be we can get
550475
/// tighter match code if we do something a bit different.
551-
pub(super) fn sort_candidate<'pat>(
476+
pub(super) fn sort_candidate(
552477
&mut self,
553478
test_place: &PlaceBuilder<'tcx>,
554479
test: &Test<'tcx>,
555-
candidate: &mut Candidate<'pat, 'tcx>,
480+
candidate: &mut Candidate<'_, 'tcx>,
481+
sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'_, 'tcx>>>,
556482
) -> Option<TestBranch<'tcx>> {
557483
// Find the match_pair for this place (if any). At present,
558484
// afaik, there can be at most one. (In the future, if we
@@ -568,7 +494,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
568494
// If we are performing a variant switch, then this
569495
// informs variant patterns, but nothing else.
570496
(
571-
&TestKind::Switch { adt_def: tested_adt_def, .. },
497+
&TestKind::Switch { adt_def: tested_adt_def },
572498
&TestCase::Variant { adt_def, variant_index },
573499
) => {
574500
assert_eq!(adt_def, tested_adt_def);
@@ -581,17 +507,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
581507
//
582508
// FIXME(#29623) we could use PatKind::Range to rule
583509
// things out here, in some cases.
584-
(TestKind::SwitchInt { options }, &TestCase::Constant { value })
510+
(TestKind::SwitchInt, &TestCase::Constant { value })
585511
if is_switch_ty(match_pair.pattern.ty) =>
586512
{
587513
fully_matched = true;
588-
let bits = options.get(&value).unwrap();
589-
Some(TestBranch::Constant(value, *bits))
514+
let bits = value.eval_bits(self.tcx, self.param_env);
515+
Some(TestBranch::Constant(value, bits))
590516
}
591-
(TestKind::SwitchInt { options }, TestCase::Range(range)) => {
517+
(TestKind::SwitchInt, TestCase::Range(range)) => {
592518
fully_matched = false;
593519
let not_contained =
594-
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
520+
sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
521+
|val| matches!(range.contains(val, self.tcx, self.param_env), Some(false)),
522+
);
595523

596524
not_contained.then(|| {
597525
// No switch values are contained in the pattern range,
@@ -732,20 +660,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
732660

733661
ret
734662
}
735-
736-
fn values_not_contained_in_range(
737-
&self,
738-
range: &PatRange<'tcx>,
739-
options: &FxIndexMap<Const<'tcx>, u128>,
740-
) -> Option<bool> {
741-
for &val in options.keys() {
742-
if range.contains(val, self.tcx, self.param_env)? {
743-
return Some(false);
744-
}
745-
}
746-
747-
Some(true)
748-
}
749663
}
750664

751665
fn is_switch_ty(ty: Ty<'_>) -> bool {

0 commit comments

Comments
 (0)