@@ -9,6 +9,14 @@ use crate::builder::Builder;
99use crate :: builder:: matches:: test:: is_switch_ty;
1010use 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+
1220impl < ' 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 ) ) ) ;
0 commit comments