Skip to content

Commit bc11e7e

Browse files
committed
Rename match-candidate partitioning methods
1 parent d602710 commit bc11e7e

File tree

2 files changed

+35
-30
lines changed

2 files changed

+35
-30
lines changed

compiler/rustc_mir_build/src/builder/matches/buckets.rs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ use crate::builder::Builder;
99
use crate::builder::matches::test::is_switch_ty;
1010
use crate::builder::matches::{Candidate, Test, TestBranch, TestCase, TestKind};
1111

12+
/// Output of [`Builder::partition_candidates_into_buckets`].
13+
pub(crate) struct PartitionedCandidates<'tcx, 'b, 'c> {
14+
/// For each possible outcome of the test, the candidates that are matched in that outcome.
15+
pub(crate) target_candidates: FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'tcx>>>,
16+
/// The remaining candidates that weren't associated with any test outcome.
17+
pub(crate) remaining_candidates: &'b mut [&'c mut Candidate<'tcx>],
18+
}
19+
1220
impl<'a, 'tcx> Builder<'a, 'tcx> {
1321
/// Given a test, we partition the input candidates into several buckets.
1422
/// If a candidate matches in exactly one of the branches of `test`
@@ -20,10 +28,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2028
/// that are entailed by the outcome of the test, and add any sub-pairs of the
2129
/// removed pairs.
2230
///
23-
/// This returns a pair of
24-
/// - the candidates that weren't sorted;
25-
/// - for each possible outcome of the test, the candidates that match in that outcome.
26-
///
2731
/// For example:
2832
/// ```
2933
/// # let (x, y, z) = (true, true, true);
@@ -41,36 +45,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4145
/// - If the outcome is that `x` is false, candidates {1, 2} are possible
4246
///
4347
/// Following our algorithm:
44-
/// - Candidate 0 is sorted into outcome `x == true`
45-
/// - Candidate 1 is sorted into outcome `x == false`
46-
/// - Candidate 2 remains unsorted, because testing `x` has no effect on it
47-
/// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
48+
/// - Candidate 0 is bucketed into outcome `x == true`
49+
/// - Candidate 1 is bucketed into outcome `x == false`
50+
/// - Candidate 2 remains unbucketed, because testing `x` has no effect on it
51+
/// - Candidate 3 remains unbucketed, because a previous candidate (2) was unbucketed
4852
/// - This helps preserve the illusion that candidates are tested "in order"
4953
///
50-
/// The sorted candidates are mutated to remove entailed match pairs:
54+
/// The bucketed candidates are mutated to remove entailed match pairs:
5155
/// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
5256
/// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
53-
pub(super) fn sort_candidates<'b, 'c>(
57+
pub(super) fn partition_candidates_into_buckets<'b, 'c>(
5458
&mut self,
5559
match_place: Place<'tcx>,
5660
test: &Test<'tcx>,
5761
mut candidates: &'b mut [&'c mut Candidate<'tcx>],
58-
) -> (
59-
&'b mut [&'c mut Candidate<'tcx>],
60-
FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'tcx>>>,
61-
) {
62-
// For each of the possible outcomes, collect vector of candidates that apply if the test
62+
) -> PartitionedCandidates<'tcx, 'b, 'c> {
63+
// For each of the possible outcomes, collect a vector of candidates that apply if the test
6364
// has that particular outcome.
6465
let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'_>>> = Default::default();
6566

6667
let total_candidate_count = candidates.len();
6768

68-
// Sort the candidates into the appropriate vector in `target_candidates`. Note that at some
69-
// point we may encounter a candidate where the test is not relevant; at that point, we stop
70-
// sorting.
69+
// Partition the candidates into the appropriate vector in `target_candidates`.
70+
// Note that at some point we may encounter a candidate where the test is not relevant;
71+
// at that point, we stop partitioning.
7172
while let Some(candidate) = candidates.first_mut() {
7273
let Some(branch) =
73-
self.sort_candidate(match_place, test, candidate, &target_candidates)
74+
self.choose_bucket_for_candidate(match_place, test, candidate, &target_candidates)
7475
else {
7576
break;
7677
};
@@ -87,7 +88,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8788
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
8889
debug!("untested_candidates: {}", candidates.len());
8990

90-
(candidates, target_candidates)
91+
PartitionedCandidates { target_candidates, remaining_candidates: candidates }
9192
}
9293

9394
/// Given that we are performing `test` against `test_place`, this job
@@ -115,12 +116,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
115116
/// that it *doesn't* apply. For now, we return false, indicate that the
116117
/// test does not apply to this candidate, but it might be we can get
117118
/// tighter match code if we do something a bit different.
118-
fn sort_candidate(
119+
fn choose_bucket_for_candidate(
119120
&mut self,
120121
test_place: Place<'tcx>,
121122
test: &Test<'tcx>,
122123
candidate: &mut Candidate<'tcx>,
123-
sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'tcx>>>,
124+
// Other candidates that have already been partitioned into a bucket for this test, if any
125+
prior_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'tcx>>>,
124126
) -> Option<TestBranch<'tcx>> {
125127
// Find the match_pair for this place (if any). At present,
126128
// afaik, there can be at most one. (In the future, if we
@@ -155,13 +157,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
155157
//
156158
// FIXME(#29623) we could use PatKind::Range to rule
157159
// things out here, in some cases.
160+
//
161+
// FIXME(Zalathar): Is the `is_switch_ty` test unnecessary?
158162
(TestKind::SwitchInt, &TestCase::Constant { value })
159163
if is_switch_ty(match_pair.pattern_ty) =>
160164
{
161-
// An important invariant of candidate sorting is that a candidate
165+
// An important invariant of candidate bucketing is that a candidate
162166
// must not match in multiple branches. For `SwitchInt` tests, adding
163167
// a new value might invalidate that property for range patterns that
164-
// have already been sorted into the failure arm, so we must take care
168+
// have already been partitioned into the failure arm, so we must take care
165169
// not to add such values here.
166170
let is_covering_range = |test_case: &TestCase<'tcx>| {
167171
test_case.as_range().is_some_and(|range| {
@@ -174,7 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
174178
.iter()
175179
.any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
176180
};
177-
if sorted_candidates
181+
if prior_candidates
178182
.get(&TestBranch::Failure)
179183
.is_some_and(|candidates| candidates.iter().any(is_conflicting_candidate))
180184
{
@@ -191,7 +195,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
191195
// the values being tested. (This restricts what values can be
192196
// added to the test by subsequent candidates.)
193197
fully_matched = false;
194-
let not_contained = sorted_candidates
198+
let not_contained = prior_candidates
195199
.keys()
196200
.filter_map(|br| br.as_constant())
197201
.all(|val| matches!(range.contains(val, self.tcx), Some(false)));

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use tracing::{debug, instrument};
2727

2828
use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard};
2929
use crate::builder::expr::as_place::PlaceBuilder;
30+
use crate::builder::matches::buckets::PartitionedCandidates;
3031
use crate::builder::matches::user_ty::ProjectedUserTypesNode;
3132
use crate::builder::scope::DropKind;
3233
use crate::builder::{
@@ -1069,7 +1070,7 @@ struct Candidate<'tcx> {
10691070
/// Key mutations include:
10701071
///
10711072
/// - When a match pair is fully satisfied by a test, it is removed from the
1072-
/// list, and its subpairs are added instead (see [`Builder::sort_candidate`]).
1073+
/// list, and its subpairs are added instead (see [`Builder::choose_bucket_for_candidate`]).
10731074
/// - During or-pattern expansion, any leading or-pattern is removed, and is
10741075
/// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
10751076
/// - After a candidate's subcandidates have been lowered, a copy of any remaining
@@ -1254,7 +1255,7 @@ struct Ascription<'tcx> {
12541255
///
12551256
/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
12561257
/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
1257-
/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair)
1258+
/// - [`Builder::choose_bucket_for_candidate`] (to see how the test interacts with a match pair)
12581259
///
12591260
/// Note that or-patterns are not tested directly like the other variants.
12601261
/// Instead they participate in or-pattern expansion, where they are transformed into
@@ -2284,8 +2285,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
22842285
// For each of the N possible test outcomes, build the vector of candidates that applies if
22852286
// the test has that particular outcome. This also mutates the candidates to remove match
22862287
// pairs that are fully satisfied by the relevant outcome.
2287-
let (remaining_candidates, target_candidates) =
2288-
self.sort_candidates(match_place, &test, candidates);
2288+
let PartitionedCandidates { target_candidates, remaining_candidates } =
2289+
self.partition_candidates_into_buckets(match_place, &test, candidates);
22892290

22902291
// The block that we should branch to if none of the `target_candidates` match.
22912292
let remainder_start = self.cfg.start_new_block();

0 commit comments

Comments
 (0)