@@ -14,7 +14,6 @@ use rustc_data_structures::{
14
14
fx:: { FxHashSet , FxIndexMap , FxIndexSet } ,
15
15
stack:: ensure_sufficient_stack,
16
16
} ;
17
- use rustc_index:: bit_set:: BitSet ;
18
17
use rustc_middle:: middle:: region;
19
18
use rustc_middle:: mir:: { self , * } ;
20
19
use rustc_middle:: thir:: { self , * } ;
@@ -1084,6 +1083,12 @@ enum TestCase<'pat, 'tcx> {
1084
1083
Or { pats : Box < [ FlatPat < ' pat , ' tcx > ] > } ,
1085
1084
}
1086
1085
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
+
1087
1092
#[ derive( Debug , Clone ) ]
1088
1093
pub ( crate ) struct MatchPair < ' pat , ' tcx > {
1089
1094
/// This place...
@@ -1108,19 +1113,10 @@ enum TestKind<'tcx> {
1108
1113
Switch {
1109
1114
/// The enum type being tested.
1110
1115
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 > ,
1114
1116
} ,
1115
1117
1116
1118
/// 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 ,
1124
1120
1125
1121
/// Test what value a `bool` has.
1126
1122
If ,
@@ -1152,6 +1148,25 @@ pub(crate) struct Test<'tcx> {
1152
1148
kind : TestKind < ' tcx > ,
1153
1149
}
1154
1150
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
+
1155
1170
/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether
1156
1171
/// a match arm has a guard expression attached to it.
1157
1172
#[ derive( Copy , Clone , Debug ) ]
@@ -1561,30 +1576,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1561
1576
) -> ( PlaceBuilder < ' tcx > , Test < ' tcx > ) {
1562
1577
// Extract the match-pair from the highest priority candidate
1563
1578
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1564
- let mut test = self . test ( match_pair) ;
1579
+ let test = self . test ( match_pair) ;
1565
1580
let match_place = match_pair. place . clone ( ) ;
1566
-
1567
1581
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
- }
1588
1582
1589
1583
( match_place, test)
1590
1584
}
@@ -1627,23 +1621,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1627
1621
match_place : & PlaceBuilder < ' tcx > ,
1628
1622
test : & Test < ' tcx > ,
1629
1623
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 ( ) ;
1635
1631
1636
1632
let total_candidate_count = candidates. len ( ) ;
1637
1633
1638
1634
// Sort the candidates into the appropriate vector in `target_candidates`. Note that at some
1639
1635
// point we may encounter a candidate where the test is not relevant; at that point, we stop
1640
1636
// sorting.
1641
1637
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 {
1643
1641
break ;
1644
1642
} ;
1645
1643
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) ;
1647
1645
candidates = rest;
1648
1646
}
1649
1647
@@ -1784,31 +1782,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1784
1782
otherwise_block
1785
1783
} ;
1786
1784
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
1792
1787
. 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)
1807
1798
} )
1808
1799
. collect ( ) ;
1809
1800
1810
1801
// 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
+ ) ;
1812
1811
}
1813
1812
1814
1813
/// Determine the fake borrows that are needed from a set of places that
0 commit comments