@@ -19,6 +19,7 @@ use build::Builder;
19
19
use build:: matches:: { Candidate , MatchPair , Test , TestKind } ;
20
20
use hair:: * ;
21
21
use rustc_data_structures:: fnv:: FnvHashMap ;
22
+ use rustc_data_structures:: bitvec:: BitVector ;
22
23
use rustc:: middle:: const_val:: ConstVal ;
23
24
use rustc:: ty:: { self , Ty } ;
24
25
use rustc:: mir:: repr:: * ;
@@ -33,7 +34,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
33
34
PatternKind :: Variant { ref adt_def, variant_index : _, subpatterns : _ } => {
34
35
Test {
35
36
span : match_pair. pattern . span ,
36
- kind : TestKind :: Switch { adt_def : adt_def. clone ( ) } ,
37
+ kind : TestKind :: Switch {
38
+ adt_def : adt_def. clone ( ) ,
39
+ variants : BitVector :: new ( self . hir . num_variants ( adt_def) ) ,
40
+ } ,
37
41
}
38
42
}
39
43
@@ -125,9 +129,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
125
129
} ) ;
126
130
true
127
131
}
128
-
132
+ PatternKind :: Variant { .. } => {
133
+ panic ! ( "you should have called add_variants_to_switch instead!" ) ;
134
+ }
129
135
PatternKind :: Range { .. } |
130
- PatternKind :: Variant { .. } |
131
136
PatternKind :: Slice { .. } |
132
137
PatternKind :: Array { .. } |
133
138
PatternKind :: Wild |
@@ -140,6 +145,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
140
145
}
141
146
}
142
147
148
+ pub fn add_variants_to_switch < ' pat > ( & mut self ,
149
+ test_lvalue : & Lvalue < ' tcx > ,
150
+ candidate : & Candidate < ' pat , ' tcx > ,
151
+ variants : & mut BitVector )
152
+ -> bool
153
+ {
154
+ let match_pair = match candidate. match_pairs . iter ( ) . find ( |mp| mp. lvalue == * test_lvalue) {
155
+ Some ( match_pair) => match_pair,
156
+ _ => { return false ; }
157
+ } ;
158
+
159
+ match * match_pair. pattern . kind {
160
+ PatternKind :: Variant { adt_def : _ , variant_index, .. } => {
161
+ // We have a pattern testing for variant `variant_index`
162
+ // set the corresponding index to true
163
+ variants. insert ( variant_index) ;
164
+ true
165
+ }
166
+ _ => {
167
+ // don't know how to add these patterns to a switch
168
+ false
169
+ }
170
+ }
171
+ }
172
+
143
173
/// Generates the code to perform a test.
144
174
pub fn perform_test ( & mut self ,
145
175
block : BasicBlock ,
@@ -148,11 +178,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
148
178
-> Vec < BasicBlock > {
149
179
let scope_id = self . innermost_scope_id ( ) ;
150
180
match test. kind {
151
- TestKind :: Switch { adt_def } => {
181
+ TestKind :: Switch { adt_def, ref variants } => {
152
182
let num_enum_variants = self . hir . num_variants ( adt_def) ;
153
- let target_blocks: Vec < _ > =
154
- ( 0 ..num_enum_variants) . map ( |_| self . cfg . start_new_block ( ) )
155
- . collect ( ) ;
183
+ let mut otherwise_block = None ;
184
+ let target_blocks: Vec < _ > = ( 0 ..num_enum_variants) . map ( |i| {
185
+ if variants. contains ( i) {
186
+ self . cfg . start_new_block ( )
187
+ } else {
188
+ if otherwise_block. is_none ( ) {
189
+ otherwise_block = Some ( self . cfg . start_new_block ( ) ) ;
190
+ }
191
+ otherwise_block. unwrap ( )
192
+ }
193
+ } ) . collect ( ) ;
194
+ debug ! ( "num_enum_variants: {}, num tested variants: {}, variants: {:?}" ,
195
+ num_enum_variants, variants. iter( ) . count( ) , variants) ;
156
196
self . cfg . terminate ( block, scope_id, test. span , TerminatorKind :: Switch {
157
197
discr : lvalue. clone ( ) ,
158
198
adt_def : adt_def,
@@ -415,7 +455,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
415
455
match test. kind {
416
456
// If we are performing a variant switch, then this
417
457
// informs variant patterns, but nothing else.
418
- TestKind :: Switch { adt_def : tested_adt_def } => {
458
+ TestKind :: Switch { adt_def : tested_adt_def , .. } => {
419
459
match * match_pair. pattern . kind {
420
460
PatternKind :: Variant { adt_def, variant_index, ref subpatterns } => {
421
461
assert_eq ! ( adt_def, tested_adt_def) ;
0 commit comments