@@ -27,13 +27,15 @@ use tracing::{debug, instrument};
2727
2828use crate :: builder:: ForGuard :: { self , OutsideGuard , RefWithinGuard } ;
2929use crate :: builder:: expr:: as_place:: PlaceBuilder ;
30+ use crate :: builder:: matches:: buckets:: PartitionedCandidates ;
3031use crate :: builder:: matches:: user_ty:: ProjectedUserTypesNode ;
3132use crate :: builder:: scope:: DropKind ;
3233use crate :: builder:: {
3334 BlockAnd , BlockAndExtension , Builder , GuardFrame , GuardFrameLocal , LocalsForNode ,
3435} ;
3536
3637// helper functions, broken out by category:
38+ mod buckets;
3739mod match_pair;
3840mod test;
3941mod user_ty;
@@ -1068,7 +1070,7 @@ struct Candidate<'tcx> {
10681070 /// Key mutations include:
10691071 ///
10701072 /// - When a match pair is fully satisfied by a test, it is removed from the
1071- /// 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 `]).
10721074 /// - During or-pattern expansion, any leading or-pattern is removed, and is
10731075 /// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
10741076 /// - After a candidate's subcandidates have been lowered, a copy of any remaining
@@ -1253,7 +1255,7 @@ struct Ascription<'tcx> {
12531255///
12541256/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
12551257/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
1256- /// - [`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)
12571259///
12581260/// Note that or-patterns are not tested directly like the other variants.
12591261/// Instead they participate in or-pattern expansion, where they are transformed into
@@ -2172,86 +2174,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21722174 ( match_place, test)
21732175 }
21742176
2175- /// Given a test, we partition the input candidates into several buckets.
2176- /// If a candidate matches in exactly one of the branches of `test`
2177- /// (and no other branches), we put it into the corresponding bucket.
2178- /// If it could match in more than one of the branches of `test`, the test
2179- /// doesn't usefully apply to it, and we stop partitioning candidates.
2180- ///
2181- /// Importantly, we also **mutate** the branched candidates to remove match pairs
2182- /// that are entailed by the outcome of the test, and add any sub-pairs of the
2183- /// removed pairs.
2184- ///
2185- /// This returns a pair of
2186- /// - the candidates that weren't sorted;
2187- /// - for each possible outcome of the test, the candidates that match in that outcome.
2188- ///
2189- /// For example:
2190- /// ```
2191- /// # let (x, y, z) = (true, true, true);
2192- /// match (x, y, z) {
2193- /// (true , _ , true ) => true, // (0)
2194- /// (false, false, _ ) => false, // (1)
2195- /// (_ , true , _ ) => true, // (2)
2196- /// (true , _ , false) => false, // (3)
2197- /// }
2198- /// # ;
2199- /// ```
2200- ///
2201- /// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets:
2202- /// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible
2203- /// - If the outcome is that `x` is false, candidates {1, 2} are possible
2204- ///
2205- /// Following our algorithm:
2206- /// - Candidate 0 is sorted into outcome `x == true`
2207- /// - Candidate 1 is sorted into outcome `x == false`
2208- /// - Candidate 2 remains unsorted, because testing `x` has no effect on it
2209- /// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
2210- /// - This helps preserve the illusion that candidates are tested "in order"
2211- ///
2212- /// The sorted candidates are mutated to remove entailed match pairs:
2213- /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
2214- /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
2215- fn sort_candidates < ' b , ' c > (
2216- & mut self ,
2217- match_place : Place < ' tcx > ,
2218- test : & Test < ' tcx > ,
2219- mut candidates : & ' b mut [ & ' c mut Candidate < ' tcx > ] ,
2220- ) -> (
2221- & ' b mut [ & ' c mut Candidate < ' tcx > ] ,
2222- FxIndexMap < TestBranch < ' tcx > , Vec < & ' b mut Candidate < ' tcx > > > ,
2223- ) {
2224- // For each of the possible outcomes, collect vector of candidates that apply if the test
2225- // has that particular outcome.
2226- let mut target_candidates: FxIndexMap < _ , Vec < & mut Candidate < ' _ > > > = Default :: default ( ) ;
2227-
2228- let total_candidate_count = candidates. len ( ) ;
2229-
2230- // Sort the candidates into the appropriate vector in `target_candidates`. Note that at some
2231- // point we may encounter a candidate where the test is not relevant; at that point, we stop
2232- // sorting.
2233- while let Some ( candidate) = candidates. first_mut ( ) {
2234- let Some ( branch) =
2235- self . sort_candidate ( match_place, test, candidate, & target_candidates)
2236- else {
2237- break ;
2238- } ;
2239- let ( candidate, rest) = candidates. split_first_mut ( ) . unwrap ( ) ;
2240- target_candidates. entry ( branch) . or_insert_with ( Vec :: new) . push ( candidate) ;
2241- candidates = rest;
2242- }
2243-
2244- // At least the first candidate ought to be tested
2245- assert ! (
2246- total_candidate_count > candidates. len( ) ,
2247- "{total_candidate_count}, {candidates:#?}"
2248- ) ;
2249- debug ! ( "tested_candidates: {}" , total_candidate_count - candidates. len( ) ) ;
2250- debug ! ( "untested_candidates: {}" , candidates. len( ) ) ;
2251-
2252- ( candidates, target_candidates)
2253- }
2254-
22552177 /// This is the most subtle part of the match lowering algorithm. At this point, there are
22562178 /// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to
22572179 /// perform some sort of test to make progress.
@@ -2363,8 +2285,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23632285 // For each of the N possible test outcomes, build the vector of candidates that applies if
23642286 // the test has that particular outcome. This also mutates the candidates to remove match
23652287 // pairs that are fully satisfied by the relevant outcome.
2366- let ( remaining_candidates , target_candidates) =
2367- self . sort_candidates ( match_place, & test, candidates) ;
2288+ let PartitionedCandidates { target_candidates, remaining_candidates } =
2289+ self . partition_candidates_into_buckets ( match_place, & test, candidates) ;
23682290
23692291 // The block that we should branch to if none of the `target_candidates` match.
23702292 let remainder_start = self . cfg . start_new_block ( ) ;
0 commit comments