6
6
// the candidates based on the result.
7
7
8
8
use crate :: build:: expr:: as_place:: PlaceBuilder ;
9
- use crate :: build:: matches:: { Candidate , MatchPair , Test , TestCase , TestKind } ;
9
+ use crate :: build:: matches:: { Candidate , MatchPair , Test , TestBranch , TestCase , TestKind } ;
10
10
use crate :: build:: Builder ;
11
11
use rustc_data_structures:: fx:: FxIndexMap ;
12
12
use rustc_hir:: { LangItem , RangeEnd } ;
@@ -129,32 +129,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
129
129
block : BasicBlock ,
130
130
place_builder : & PlaceBuilder < ' tcx > ,
131
131
test : & Test < ' tcx > ,
132
- target_blocks : Vec < BasicBlock > ,
132
+ target_blocks : FxIndexMap < TestBranch < ' tcx > , BasicBlock > ,
133
133
) {
134
134
let place = place_builder. to_place ( self ) ;
135
135
let place_ty = place. ty ( & self . local_decls , self . tcx ) ;
136
- debug ! ( ?place, ?place_ty, ) ;
136
+ debug ! ( ?place, ?place_ty) ;
137
+ let target_block = |branch| target_blocks[ & branch] ;
137
138
138
139
let source_info = self . source_info ( test. span ) ;
139
140
match test. kind {
140
141
TestKind :: Switch { adt_def, ref variants } => {
141
142
// Variants is a BitVec of indexes into adt_def.variants.
142
143
let num_enum_variants = adt_def. variants ( ) . len ( ) ;
143
144
debug_assert_eq ! ( target_blocks. len( ) , num_enum_variants + 1 ) ;
144
- let otherwise_block = * target_blocks . last ( ) . unwrap ( ) ;
145
+ let otherwise_block = target_block ( TestBranch :: Failure ) ;
145
146
let tcx = self . tcx ;
146
147
let switch_targets = SwitchTargets :: new (
147
148
adt_def. discriminants ( tcx) . filter_map ( |( idx, discr) | {
148
149
if variants. contains ( idx) {
149
150
debug_assert_ne ! (
150
- target_blocks [ idx . index ( ) ] ,
151
+ target_block ( TestBranch :: Variant ( idx ) ) ,
151
152
otherwise_block,
152
153
"no candidates for tested discriminant: {discr:?}" ,
153
154
) ;
154
- Some ( ( discr. val , target_blocks [ idx . index ( ) ] ) )
155
+ Some ( ( discr. val , target_block ( TestBranch :: Variant ( idx ) ) ) )
155
156
} else {
156
157
debug_assert_eq ! (
157
- target_blocks [ idx . index ( ) ] ,
158
+ target_block ( TestBranch :: Variant ( idx ) ) ,
158
159
otherwise_block,
159
160
"found candidates for untested discriminant: {discr:?}" ,
160
161
) ;
@@ -185,9 +186,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
185
186
TestKind :: SwitchInt { ref options } => {
186
187
// The switch may be inexhaustive so we have a catch-all block
187
188
debug_assert_eq ! ( options. len( ) + 1 , target_blocks. len( ) ) ;
188
- let otherwise_block = * target_blocks . last ( ) . unwrap ( ) ;
189
+ let otherwise_block = target_block ( TestBranch :: Failure ) ;
189
190
let switch_targets = SwitchTargets :: new (
190
- options. values ( ) . copied ( ) . zip ( target_blocks) ,
191
+ options
192
+ . iter ( )
193
+ . map ( |( & val, & bits) | ( bits, target_block ( TestBranch :: Constant ( val, bits) ) ) ) ,
191
194
otherwise_block,
192
195
) ;
193
196
let terminator = TerminatorKind :: SwitchInt {
@@ -198,18 +201,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
198
201
}
199
202
200
203
TestKind :: If => {
201
- let [ false_bb, true_bb] = * target_blocks else {
202
- bug ! ( "`TestKind::If` should have two targets" )
203
- } ;
204
- let terminator = TerminatorKind :: if_ ( Operand :: Copy ( place) , true_bb, false_bb) ;
204
+ debug_assert_eq ! ( target_blocks. len( ) , 2 ) ;
205
+ let success_block = target_block ( TestBranch :: Success ) ;
206
+ let fail_block = target_block ( TestBranch :: Failure ) ;
207
+ let terminator =
208
+ TerminatorKind :: if_ ( Operand :: Copy ( place) , success_block, fail_block) ;
205
209
self . cfg . terminate ( block, self . source_info ( match_start_span) , terminator) ;
206
210
}
207
211
208
212
TestKind :: Eq { value, ty } => {
209
213
let tcx = self . tcx ;
210
- let [ success_block , fail_block ] = * target_blocks else {
211
- bug ! ( "`TestKind::Eq` should have two target blocks" )
212
- } ;
214
+ debug_assert_eq ! ( target_blocks . len ( ) , 2 ) ;
215
+ let success_block = target_block ( TestBranch :: Success ) ;
216
+ let fail_block = target_block ( TestBranch :: Failure ) ;
213
217
if let ty:: Adt ( def, _) = ty. kind ( )
214
218
&& Some ( def. did ( ) ) == tcx. lang_items ( ) . string ( )
215
219
{
@@ -286,9 +290,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
286
290
}
287
291
288
292
TestKind :: Range ( ref range) => {
289
- let [ success , fail ] = * target_blocks else {
290
- bug ! ( "`TestKind::Range` should have two target blocks" ) ;
291
- } ;
293
+ debug_assert_eq ! ( target_blocks . len ( ) , 2 ) ;
294
+ let success = target_block ( TestBranch :: Success ) ;
295
+ let fail = target_block ( TestBranch :: Failure ) ;
292
296
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
293
297
let val = Operand :: Copy ( place) ;
294
298
@@ -333,15 +337,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
333
337
// expected = <N>
334
338
let expected = self . push_usize ( block, source_info, len) ;
335
339
336
- let [ true_bb , false_bb ] = * target_blocks else {
337
- bug ! ( "`TestKind::Len` should have two target blocks" ) ;
338
- } ;
340
+ debug_assert_eq ! ( target_blocks . len ( ) , 2 ) ;
341
+ let success_block = target_block ( TestBranch :: Success ) ;
342
+ let fail_block = target_block ( TestBranch :: Failure ) ;
339
343
// result = actual == expected OR result = actual < expected
340
344
// branch based on result
341
345
self . compare (
342
346
block,
343
- true_bb ,
344
- false_bb ,
347
+ success_block ,
348
+ fail_block ,
345
349
source_info,
346
350
op,
347
351
Operand :: Move ( actual) ,
@@ -526,10 +530,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
526
530
527
531
/// Given that we are performing `test` against `test_place`, this job
528
532
/// sorts out what the status of `candidate` will be after the test. See
529
- /// `test_candidates` for the usage of this function. The returned index is
530
- /// the index that this candidate should be placed in the
531
- /// `target_candidates` vec. The candidate may be modified to update its
532
- /// `match_pairs`.
533
+ /// `test_candidates` for the usage of this function. The candidate may
534
+ /// be modified to update its `match_pairs`.
533
535
///
534
536
/// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
535
537
/// a variant test, then we would modify the candidate to be `(x as
@@ -556,7 +558,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
556
558
test_place : & PlaceBuilder < ' tcx > ,
557
559
test : & Test < ' tcx > ,
558
560
candidate : & mut Candidate < ' pat , ' tcx > ,
559
- ) -> Option < usize > {
561
+ ) -> Option < TestBranch < ' tcx > > {
560
562
// Find the match_pair for this place (if any). At present,
561
563
// afaik, there can be at most one. (In the future, if we
562
564
// adopted a more general `@` operator, there might be more
@@ -576,20 +578,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
576
578
) => {
577
579
assert_eq ! ( adt_def, tested_adt_def) ;
578
580
fully_matched = true ;
579
- Some ( variant_index . as_usize ( ) )
581
+ Some ( TestBranch :: Variant ( variant_index ) )
580
582
}
581
583
582
584
// If we are performing a switch over integers, then this informs integer
583
585
// equality, but nothing else.
584
586
//
585
587
// FIXME(#29623) we could use PatKind::Range to rule
586
588
// things out here, in some cases.
587
- ( TestKind :: SwitchInt { options } , TestCase :: Constant { value } )
589
+ ( TestKind :: SwitchInt { options } , & TestCase :: Constant { value } )
588
590
if is_switch_ty ( match_pair. pattern . ty ) =>
589
591
{
590
592
fully_matched = true ;
591
- let index = options. get_index_of ( value) . unwrap ( ) ;
592
- Some ( index )
593
+ let bits = options. get ( & value) . unwrap ( ) ;
594
+ Some ( TestBranch :: Constant ( value , * bits ) )
593
595
}
594
596
( TestKind :: SwitchInt { options } , TestCase :: Range ( range) ) => {
595
597
fully_matched = false ;
@@ -599,7 +601,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
599
601
not_contained. then ( || {
600
602
// No switch values are contained in the pattern range,
601
603
// so the pattern can be matched only if this test fails.
602
- options . len ( )
604
+ TestBranch :: Failure
603
605
} )
604
606
}
605
607
@@ -608,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
608
610
let value = value. try_eval_bool ( self . tcx , self . param_env ) . unwrap_or_else ( || {
609
611
span_bug ! ( test. span, "expected boolean value but got {value:?}" )
610
612
} ) ;
611
- Some ( value as usize )
613
+ Some ( if value { TestBranch :: Success } else { TestBranch :: Failure } )
612
614
}
613
615
614
616
(
@@ -620,14 +622,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
620
622
// on true, min_len = len = $actual_length,
621
623
// on false, len != $actual_length
622
624
fully_matched = true ;
623
- Some ( 0 )
625
+ Some ( TestBranch :: Success )
624
626
}
625
627
( Ordering :: Less , _) => {
626
628
// test_len < pat_len. If $actual_len = test_len,
627
629
// then $actual_len < pat_len and we don't have
628
630
// enough elements.
629
631
fully_matched = false ;
630
- Some ( 1 )
632
+ Some ( TestBranch :: Failure )
631
633
}
632
634
( Ordering :: Equal | Ordering :: Greater , true ) => {
633
635
// This can match both if $actual_len = test_len >= pat_len,
@@ -639,7 +641,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
639
641
// test_len != pat_len, so if $actual_len = test_len, then
640
642
// $actual_len != pat_len.
641
643
fully_matched = false ;
642
- Some ( 1 )
644
+ Some ( TestBranch :: Failure )
643
645
}
644
646
}
645
647
}
@@ -653,20 +655,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
653
655
// $actual_len >= test_len = pat_len,
654
656
// so we can match.
655
657
fully_matched = true ;
656
- Some ( 0 )
658
+ Some ( TestBranch :: Success )
657
659
}
658
660
( Ordering :: Less , _) | ( Ordering :: Equal , false ) => {
659
661
// test_len <= pat_len. If $actual_len < test_len,
660
662
// then it is also < pat_len, so the test passing is
661
663
// necessary (but insufficient).
662
664
fully_matched = false ;
663
- Some ( 0 )
665
+ Some ( TestBranch :: Success )
664
666
}
665
667
( Ordering :: Greater , false ) => {
666
668
// test_len > pat_len. If $actual_len >= test_len > pat_len,
667
669
// then we know we won't have a match.
668
670
fully_matched = false ;
669
- Some ( 1 )
671
+ Some ( TestBranch :: Failure )
670
672
}
671
673
( Ordering :: Greater , true ) => {
672
674
// test_len < pat_len, and is therefore less
@@ -680,20 +682,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
680
682
( TestKind :: Range ( test) , & TestCase :: Range ( pat) ) => {
681
683
if test. as_ref ( ) == pat {
682
684
fully_matched = true ;
683
- Some ( 0 )
685
+ Some ( TestBranch :: Success )
684
686
} else {
685
687
fully_matched = false ;
686
688
// If the testing range does not overlap with pattern range,
687
689
// the pattern can be matched only if this test fails.
688
- if !test. overlaps ( pat, self . tcx , self . param_env ) ? { Some ( 1 ) } else { None }
690
+ if !test. overlaps ( pat, self . tcx , self . param_env ) ? {
691
+ Some ( TestBranch :: Failure )
692
+ } else {
693
+ None
694
+ }
689
695
}
690
696
}
691
697
( TestKind :: Range ( range) , & TestCase :: Constant { value } ) => {
692
698
fully_matched = false ;
693
699
if !range. contains ( value, self . tcx , self . param_env ) ? {
694
700
// `value` is not contained in the testing range,
695
701
// so `value` can be matched only if this test fails.
696
- Some ( 1 )
702
+ Some ( TestBranch :: Failure )
697
703
} else {
698
704
None
699
705
}
@@ -704,7 +710,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
704
710
if test_val == case_val =>
705
711
{
706
712
fully_matched = true ;
707
- Some ( 0 )
713
+ Some ( TestBranch :: Success )
708
714
}
709
715
710
716
(
@@ -747,18 +753,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
747
753
}
748
754
}
749
755
750
- impl Test < ' _ > {
751
- pub ( super ) fn targets ( & self ) -> usize {
756
+ impl < ' tcx > Test < ' tcx > {
757
+ pub ( super ) fn targets ( & self ) -> Vec < TestBranch < ' tcx > > {
752
758
match self . kind {
753
- TestKind :: Eq { .. } | TestKind :: Range ( _) | TestKind :: Len { .. } | TestKind :: If => 2 ,
759
+ TestKind :: Eq { .. } | TestKind :: Range ( _) | TestKind :: Len { .. } | TestKind :: If => {
760
+ vec ! [ TestBranch :: Success , TestBranch :: Failure ]
761
+ }
754
762
TestKind :: Switch { adt_def, .. } => {
755
763
// While the switch that we generate doesn't test for all
756
764
// variants, we have a target for each variant and the
757
765
// otherwise case, and we make sure that all of the cases not
758
766
// specified have the same block.
759
- adt_def. variants ( ) . len ( ) + 1
767
+ adt_def
768
+ . variants ( )
769
+ . indices ( )
770
+ . map ( |idx| TestBranch :: Variant ( idx) )
771
+ . chain ( [ TestBranch :: Failure ] )
772
+ . collect ( )
760
773
}
761
- TestKind :: SwitchInt { ref options } => options. len ( ) + 1 ,
774
+ TestKind :: SwitchInt { ref options } => options
775
+ . iter ( )
776
+ . map ( |( val, bits) | TestBranch :: Constant ( * val, * bits) )
777
+ . chain ( [ TestBranch :: Failure ] )
778
+ . collect ( ) ,
762
779
}
763
780
}
764
781
}
0 commit comments