@@ -205,33 +205,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
205
205
. flat_map ( |( _, candidates) | candidates)
206
206
. collect :: < Vec < _ > > ( ) ;
207
207
208
+ let outer_source_info = self . source_info ( span) ;
209
+
208
210
// this will generate code to test scrutinee_place and
209
211
// branch to the appropriate arm block
210
- let otherwise = self . match_candidates (
212
+ self . match_candidates (
211
213
scrutinee_span,
214
+ & mut Some ( block) ,
215
+ None ,
212
216
candidates,
213
- block,
214
217
& mut fake_borrows,
215
218
) ;
216
219
217
- let outer_source_info = self . source_info ( span) ;
218
-
219
- if !otherwise. is_empty ( ) {
220
- // All matches are exhaustive. However, because some matches
221
- // only have exponentially-large exhaustive decision trees, we
222
- // sometimes generate an inexhaustive decision tree.
223
- //
224
- // In that case, the inexhaustive tips of the decision tree
225
- // can't be reached - terminate them with an `unreachable`.
226
- let mut otherwise = otherwise;
227
- otherwise. sort ( ) ;
228
- otherwise. dedup ( ) ; // variant switches can introduce duplicate target blocks
229
- for block in otherwise {
230
- self . cfg
231
- . terminate ( block, outer_source_info, TerminatorKind :: Unreachable ) ;
232
- }
233
- }
234
-
235
220
// Step 4. Determine the fake borrows that are needed from the above
236
221
// places. Create the required temporaries for them.
237
222
@@ -264,19 +249,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
264
249
) ;
265
250
} else {
266
251
arm_block = self . cfg . start_new_block ( ) ;
267
- for candidate in candidates {
252
+ for candidate in candidates {
268
253
let binding_end = self . bind_and_guard_matched_candidate (
269
- candidate,
270
- arm. guard . clone ( ) ,
271
- & fake_borrow_temps,
272
- scrutinee_span,
273
- ) ;
254
+ candidate,
255
+ arm. guard . clone ( ) ,
256
+ & fake_borrow_temps,
257
+ scrutinee_span,
258
+ ) ;
274
259
self . cfg . terminate (
275
260
binding_end,
276
261
source_info,
277
262
TerminatorKind :: Goto { target : arm_block } ,
278
263
) ;
279
- }
264
+ }
280
265
}
281
266
282
267
if let Some ( source_scope) = scope {
@@ -793,11 +778,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
793
778
/// the value, we will generate a branch to the appropriate
794
779
/// prebinding block.
795
780
///
796
- /// The return value is a list of "otherwise" blocks. These are
797
- /// points in execution where we found that *NONE* of the
798
- /// candidates apply. In principle, this means that the input
799
- /// list was not exhaustive, though at present we sometimes are
800
- /// not smart enough to recognize all exhaustive inputs.
781
+ /// If we find that *NONE* of the candidates apply, we branch to the
782
+ /// `otherwise_block`. In principle, this means that the input list was not
783
+ /// exhaustive, though at present we sometimes are not smart enough to
784
+ /// recognize all exhaustive inputs.
801
785
///
802
786
/// It might be surprising that the input can be inexhaustive.
803
787
/// Indeed, initially, it is not, because all matches are
@@ -811,13 +795,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
811
795
fn match_candidates < ' pat > (
812
796
& mut self ,
813
797
span : Span ,
798
+ start_block : & mut Option < BasicBlock > ,
799
+ otherwise_block : Option < BasicBlock > ,
814
800
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
815
- mut block : BasicBlock ,
816
801
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
817
- ) -> Vec < BasicBlock > {
802
+ ) {
818
803
debug ! (
819
- "matched_candidate(span={:?}, block={:?}, candidates={:?})" ,
820
- span, block, candidates
804
+ "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})" ,
805
+ span,
806
+ candidates,
807
+ start_block,
808
+ otherwise_block,
821
809
) ;
822
810
823
811
// Start by simplifying candidates. Once this process is complete, all
@@ -840,52 +828,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
840
828
) ;
841
829
let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
842
830
831
+ let block: BasicBlock ;
832
+
843
833
if !matched_candidates. is_empty ( ) {
844
- block = if let Some ( last_otherwise_block ) = self . select_matched_candidates (
834
+ let otherwise_block = self . select_matched_candidates (
845
835
matched_candidates,
846
- block ,
836
+ start_block ,
847
837
fake_borrows,
848
- ) {
849
- last_otherwise_block
838
+ ) ;
839
+
840
+ if let Some ( last_otherwise_block) = otherwise_block {
841
+ block = last_otherwise_block
850
842
} else {
851
843
// Any remaining candidates are unreachable.
852
844
if unmatched_candidates. is_empty ( ) {
853
- return Vec :: new ( ) ;
854
- } else {
855
- self . cfg . start_new_block ( )
845
+ return ;
856
846
}
847
+ block = self . cfg . start_new_block ( ) ;
857
848
} ;
849
+ } else {
850
+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
858
851
}
859
852
860
853
// If there are no candidates that still need testing, we're
861
854
// done. Since all matches are exhaustive, execution should
862
855
// never reach this point.
863
856
if unmatched_candidates. is_empty ( ) {
864
- return vec ! [ block] ;
857
+ let source_info = self . source_info ( span) ;
858
+ if let Some ( otherwise) = otherwise_block {
859
+ self . cfg . terminate (
860
+ block,
861
+ source_info,
862
+ TerminatorKind :: Goto { target : otherwise } ,
863
+ ) ;
864
+ } else {
865
+ self . cfg . terminate (
866
+ block,
867
+ source_info,
868
+ TerminatorKind :: Unreachable ,
869
+ )
870
+ }
871
+ return ;
865
872
}
866
873
867
- // Test candidates where possible .
868
- let ( otherwise , untested_candidates ) = self . test_candidates (
874
+ // Test for the remaining candidates .
875
+ self . test_candidates (
869
876
span,
870
877
unmatched_candidates,
871
878
block,
879
+ otherwise_block,
872
880
fake_borrows,
873
881
) ;
874
-
875
- // If the target candidates were exhaustive, then we are done.
876
- // But for borrowck continue build decision tree.
877
- if untested_candidates. is_empty ( ) {
878
- return otherwise;
879
- }
880
-
881
- // Otherwise, let's process those remaining candidates.
882
- let join_block = self . join_otherwise_blocks ( span, otherwise) ;
883
- self . match_candidates (
884
- span,
885
- untested_candidates,
886
- join_block,
887
- & mut None ,
888
- )
889
882
}
890
883
891
884
/// Link up matched candidates. For example, if we have something like
@@ -909,7 +902,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
909
902
fn select_matched_candidates (
910
903
& mut self ,
911
904
matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
912
- block : BasicBlock ,
905
+ start_block : & mut Option < BasicBlock > ,
913
906
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
914
907
) -> Option < BasicBlock > {
915
908
debug_assert ! (
@@ -957,16 +950,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
957
950
= matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
958
951
959
952
let first_candidate = & reachable_candidates[ 0 ] ;
953
+ let first_prebinding_block = first_candidate. pre_binding_block ;
960
954
961
- let candidate_source_info = self . source_info ( first_candidate. span ) ;
962
-
963
- self . cfg . terminate (
964
- block,
965
- candidate_source_info,
966
- TerminatorKind :: Goto {
967
- target : first_candidate. pre_binding_block ,
968
- } ,
969
- ) ;
955
+ if let Some ( start_block) = * start_block {
956
+ let source_info = self . source_info ( first_candidate. span ) ;
957
+ self . cfg . terminate (
958
+ start_block,
959
+ source_info,
960
+ TerminatorKind :: Goto { target : first_prebinding_block } ,
961
+ ) ;
962
+ } else {
963
+ * start_block = Some ( first_prebinding_block) ;
964
+ }
970
965
971
966
for window in reachable_candidates. windows ( 2 ) {
972
967
if let [ first_candidate, second_candidate] = window {
@@ -1018,25 +1013,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1018
1013
}
1019
1014
}
1020
1015
1021
- fn join_otherwise_blocks ( & mut self , span : Span , mut otherwise : Vec < BasicBlock > ) -> BasicBlock {
1022
- let source_info = self . source_info ( span) ;
1023
- otherwise. sort ( ) ;
1024
- otherwise. dedup ( ) ; // variant switches can introduce duplicate target blocks
1025
- if otherwise. len ( ) == 1 {
1026
- otherwise[ 0 ]
1027
- } else {
1028
- let join_block = self . cfg . start_new_block ( ) ;
1029
- for block in otherwise {
1030
- self . cfg . terminate (
1031
- block,
1032
- source_info,
1033
- TerminatorKind :: Goto { target : join_block } ,
1034
- ) ;
1035
- }
1036
- join_block
1037
- }
1038
- }
1039
-
1040
1016
/// This is the most subtle part of the matching algorithm. At
1041
1017
/// this point, the input candidates have been fully simplified,
1042
1018
/// and so we know that all remaining match-pairs require some
@@ -1154,8 +1130,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1154
1130
span : Span ,
1155
1131
mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1156
1132
block : BasicBlock ,
1133
+ mut otherwise_block : Option < BasicBlock > ,
1157
1134
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1158
- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1135
+ ) {
1159
1136
// extract the match-pair from the highest priority candidate
1160
1137
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1161
1138
let mut test = self . test ( match_pair) ;
@@ -1209,9 +1186,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1209
1186
"match_candidates: test={:?} match_pair={:?}" ,
1210
1187
test, match_pair
1211
1188
) ;
1212
- let target_blocks = self . perform_test ( block, & match_place, & test) ;
1213
1189
let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
1214
- target_candidates. resize_with ( target_blocks . len ( ) , Default :: default) ;
1190
+ target_candidates. resize_with ( test . targets ( ) , Default :: default) ;
1215
1191
1216
1192
let total_candidate_count = candidates. len ( ) ;
1217
1193
@@ -1237,20 +1213,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1237
1213
// apply. Collect a list of blocks where control flow will
1238
1214
// branch if one of the `target_candidate` sets is not
1239
1215
// exhaustive.
1240
- let otherwise: Vec < _ > = target_blocks
1241
- . into_iter ( )
1242
- . zip ( target_candidates)
1243
- . flat_map ( |( target_block, mut target_candidates) | {
1216
+ if !candidates. is_empty ( ) {
1217
+ let remainder_start = & mut None ;
1218
+ self . match_candidates (
1219
+ span,
1220
+ remainder_start,
1221
+ otherwise_block,
1222
+ candidates,
1223
+ fake_borrows,
1224
+ ) ;
1225
+ otherwise_block = Some ( remainder_start. unwrap ( ) ) ;
1226
+ } ;
1227
+ let target_blocks: Vec < _ > = target_candidates. into_iter ( ) . map ( |mut candidates| {
1228
+ if candidates. len ( ) != 0 {
1229
+ let candidate_start = & mut None ;
1244
1230
self . match_candidates (
1245
1231
span,
1246
- & mut * target_candidates,
1247
- target_block,
1232
+ candidate_start,
1233
+ otherwise_block,
1234
+ & mut * candidates,
1248
1235
fake_borrows,
1249
- )
1250
- } )
1251
- . collect ( ) ;
1236
+ ) ;
1237
+ candidate_start. unwrap ( )
1238
+ } else {
1239
+ * otherwise_block. get_or_insert_with ( || {
1240
+ let unreachable = self . cfg . start_new_block ( ) ;
1241
+ let source_info = self . source_info ( span) ;
1242
+ self . cfg . terminate (
1243
+ unreachable,
1244
+ source_info,
1245
+ TerminatorKind :: Unreachable ,
1246
+ ) ;
1247
+ unreachable
1248
+ } )
1249
+ }
1250
+ } ) . collect ( ) ;
1252
1251
1253
- ( otherwise, candidates)
1252
+ self . perform_test (
1253
+ block,
1254
+ & match_place,
1255
+ & test,
1256
+ target_blocks,
1257
+ ) ;
1254
1258
}
1255
1259
1256
1260
// Determine the fake borrows that are needed to ensure that the place
@@ -1344,10 +1348,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1344
1348
block,
1345
1349
fresh_block,
1346
1350
candidate. next_candidate_pre_binding_block ,
1347
- candidate_source_info,
1348
- ) ;
1351
+ candidate_source_info,
1352
+ ) ;
1349
1353
block = fresh_block;
1350
- self . ascribe_types ( block, & candidate. ascriptions ) ;
1354
+ self . ascribe_types ( block, & candidate. ascriptions ) ;
1351
1355
} else {
1352
1356
return block;
1353
1357
}
0 commit comments