@@ -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 ;
1817use rustc_middle:: middle:: region;
1918use rustc_middle:: mir:: { self , * } ;
2019use rustc_middle:: thir:: { self , * } ;
@@ -1084,6 +1083,12 @@ enum TestCase<'pat, 'tcx> {
10841083 Or { pats : Box < [ FlatPat < ' pat , ' tcx > ] > } ,
10851084}
10861085
1086+ impl < ' pat , ' tcx > TestCase < ' pat , ' tcx > {
1087+ fn as_range ( & self ) -> Option < & ' pat PatRange < ' tcx > > {
1088+ if let Self :: Range ( v) = self { Some ( * v) } else { None }
1089+ }
1090+ }
1091+
10871092#[ derive( Debug , Clone ) ]
10881093pub ( crate ) struct MatchPair < ' pat , ' tcx > {
10891094 /// This place...
@@ -1108,19 +1113,10 @@ enum TestKind<'tcx> {
11081113 Switch {
11091114 /// The enum type being tested.
11101115 adt_def : ty:: AdtDef < ' tcx > ,
1111- /// The set of variants that we should create a branch for. We also
1112- /// create an additional "otherwise" case.
1113- variants : BitSet < VariantIdx > ,
11141116 } ,
11151117
11161118 /// Test what value an integer or `char` has.
1117- SwitchInt {
1118- /// The (ordered) set of values that we test for.
1119- ///
1120- /// We create a branch to each of the values in `options`, as well as an "otherwise" branch
1121- /// for all other values, even in the (rare) case that `options` is exhaustive.
1122- options : FxIndexMap < Const < ' tcx > , u128 > ,
1123- } ,
1119+ SwitchInt ,
11241120
11251121 /// Test what value a `bool` has.
11261122 If ,
@@ -1152,6 +1148,25 @@ pub(crate) struct Test<'tcx> {
11521148 kind : TestKind < ' tcx > ,
11531149}
11541150
1151+ /// The branch to be taken after a test.
1152+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
1153+ enum TestBranch < ' tcx > {
1154+ /// Success branch, used for tests with two possible outcomes.
1155+ Success ,
1156+ /// Branch corresponding to this constant.
1157+ Constant ( Const < ' tcx > , u128 ) ,
1158+ /// Branch corresponding to this variant.
1159+ Variant ( VariantIdx ) ,
1160+ /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests.
1161+ Failure ,
1162+ }
1163+
1164+ impl < ' tcx > TestBranch < ' tcx > {
1165+ fn as_constant ( & self ) -> Option < & Const < ' tcx > > {
1166+ if let Self :: Constant ( v, _) = self { Some ( v) } else { None }
1167+ }
1168+ }
1169+
11551170/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether
11561171/// a match arm has a guard expression attached to it.
11571172#[ derive( Copy , Clone , Debug ) ]
@@ -1561,30 +1576,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15611576 ) -> ( PlaceBuilder < ' tcx > , Test < ' tcx > ) {
15621577 // Extract the match-pair from the highest priority candidate
15631578 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1564- let mut test = self . test ( match_pair) ;
1579+ let test = self . test ( match_pair) ;
15651580 let match_place = match_pair. place . clone ( ) ;
1566-
15671581 debug ! ( ?test, ?match_pair) ;
1568- // Most of the time, the test to perform is simply a function of the main candidate; but for
1569- // a test like SwitchInt, we may want to add cases based on the candidates that are
1570- // available
1571- match test. kind {
1572- TestKind :: SwitchInt { ref mut options } => {
1573- for candidate in candidates. iter ( ) {
1574- if !self . add_cases_to_switch ( & match_place, candidate, options) {
1575- break ;
1576- }
1577- }
1578- }
1579- TestKind :: Switch { adt_def : _, ref mut variants } => {
1580- for candidate in candidates. iter ( ) {
1581- if !self . add_variants_to_switch ( & match_place, candidate, variants) {
1582- break ;
1583- }
1584- }
1585- }
1586- _ => { }
1587- }
15881582
15891583 ( match_place, test)
15901584 }
@@ -1627,23 +1621,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16271621 match_place : & PlaceBuilder < ' tcx > ,
16281622 test : & Test < ' tcx > ,
16291623 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1630- ) -> ( & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] , Vec < Vec < & ' b mut Candidate < ' pat , ' tcx > > > ) {
1631- // For each of the N possible outcomes, create a (initially empty) vector of candidates.
1632- // Those are the candidates that apply if the test has that particular outcome.
1633- let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
1634- target_candidates. resize_with ( test. targets ( ) , Default :: default) ;
1624+ ) -> (
1625+ & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1626+ FxIndexMap < TestBranch < ' tcx > , Vec < & ' b mut Candidate < ' pat , ' tcx > > > ,
1627+ ) {
1628+ // For each of the possible outcomes, collect vector of candidates that apply if the test
1629+ // has that particular outcome.
1630+ let mut target_candidates: FxIndexMap < _ , Vec < & mut Candidate < ' _ , ' _ > > > = Default :: default ( ) ;
16351631
16361632 let total_candidate_count = candidates. len ( ) ;
16371633
16381634 // Sort the candidates into the appropriate vector in `target_candidates`. Note that at some
16391635 // point we may encounter a candidate where the test is not relevant; at that point, we stop
16401636 // sorting.
16411637 while let Some ( candidate) = candidates. first_mut ( ) {
1642- let Some ( idx) = self . sort_candidate ( & match_place, & test, candidate) else {
1638+ let Some ( branch) =
1639+ self . sort_candidate ( & match_place, test, candidate, & target_candidates)
1640+ else {
16431641 break ;
16441642 } ;
16451643 let ( candidate, rest) = candidates. split_first_mut ( ) . unwrap ( ) ;
1646- target_candidates[ idx ] . push ( candidate) ;
1644+ target_candidates. entry ( branch ) . or_insert_with ( Vec :: new ) . push ( candidate) ;
16471645 candidates = rest;
16481646 }
16491647
@@ -1784,31 +1782,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17841782 otherwise_block
17851783 } ;
17861784
1787- // For each outcome of test, process the candidates that still
1788- // apply. Collect a list of blocks where control flow will
1789- // branch if one of the `target_candidate` sets is not
1790- // exhaustive.
1791- let target_blocks: Vec < _ > = target_candidates
1785+ // For each outcome of test, process the candidates that still apply.
1786+ let target_blocks: FxIndexMap < _ , _ > = target_candidates
17921787 . into_iter ( )
1793- . map ( |mut candidates| {
1794- if !candidates. is_empty ( ) {
1795- let candidate_start = self . cfg . start_new_block ( ) ;
1796- self . match_candidates (
1797- span,
1798- scrutinee_span,
1799- candidate_start,
1800- remainder_start,
1801- & mut * candidates,
1802- ) ;
1803- candidate_start
1804- } else {
1805- remainder_start
1806- }
1788+ . map ( |( branch, mut candidates) | {
1789+ let candidate_start = self . cfg . start_new_block ( ) ;
1790+ self . match_candidates (
1791+ span,
1792+ scrutinee_span,
1793+ candidate_start,
1794+ remainder_start,
1795+ & mut * candidates,
1796+ ) ;
1797+ ( branch, candidate_start)
18071798 } )
18081799 . collect ( ) ;
18091800
18101801 // Perform the test, branching to one of N blocks.
1811- self . perform_test ( span, scrutinee_span, start_block, & match_place, & test, target_blocks) ;
1802+ self . perform_test (
1803+ span,
1804+ scrutinee_span,
1805+ start_block,
1806+ remainder_start,
1807+ & match_place,
1808+ & test,
1809+ target_blocks,
1810+ ) ;
18121811 }
18131812
18141813 /// Determine the fake borrows that are needed from a set of places that
0 commit comments