@@ -206,33 +206,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206
206
. flat_map ( |( _, candidates) | candidates)
207
207
. collect :: < Vec < _ > > ( ) ;
208
208
209
+ let outer_source_info = self . source_info ( span) ;
210
+
209
211
// this will generate code to test scrutinee_place and
210
212
// branch to the appropriate arm block
211
- let otherwise = self . match_candidates (
213
+ self . match_candidates (
212
214
scrutinee_span,
215
+ & mut Some ( block) ,
216
+ None ,
213
217
candidates,
214
- block,
215
218
& mut fake_borrows,
216
219
) ;
217
220
218
- let outer_source_info = self . source_info ( span) ;
219
-
220
- if !otherwise. is_empty ( ) {
221
- // All matches are exhaustive. However, because some matches
222
- // only have exponentially-large exhaustive decision trees, we
223
- // sometimes generate an inexhaustive decision tree.
224
- //
225
- // In that case, the inexhaustive tips of the decision tree
226
- // can't be reached - terminate them with an `unreachable`.
227
- let mut otherwise = otherwise;
228
- otherwise. sort ( ) ;
229
- otherwise. dedup ( ) ; // variant switches can introduce duplicate target blocks
230
- for block in otherwise {
231
- self . cfg
232
- . terminate ( block, outer_source_info, TerminatorKind :: Unreachable ) ;
233
- }
234
- }
235
-
236
221
// Step 4. Determine the fake borrows that are needed from the above
237
222
// places. Create the required temporaries for them.
238
223
@@ -247,8 +232,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
247
232
let arm_source_info = self . source_info ( arm. span ) ;
248
233
let region_scope = ( arm. scope , arm_source_info) ;
249
234
self . in_scope ( region_scope, arm. lint_level , |this| {
250
- let mut arm_block = this. cfg . start_new_block ( ) ;
251
-
252
235
let body = this. hir . mirror ( arm. body . clone ( ) ) ;
253
236
let scope = this. declare_bindings (
254
237
None ,
@@ -258,23 +241,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
258
241
Some ( ( Some ( & scrutinee_place) , scrutinee_span) ) ,
259
242
) ;
260
243
244
+ let arm_block;
261
245
if candidates. len ( ) == 1 {
262
- arm_block = self . bind_and_guard_matched_candidate (
246
+ arm_block = this . bind_and_guard_matched_candidate (
263
247
candidates. pop ( ) . unwrap ( ) ,
264
248
arm. guard . clone ( ) ,
265
249
& fake_borrow_temps,
266
250
scrutinee_span,
251
+ region_scope,
267
252
) ;
268
253
} else {
269
- arm_block = self . cfg . start_new_block ( ) ;
254
+ arm_block = this . cfg . start_new_block ( ) ;
270
255
for candidate in candidates {
271
- let binding_end = self . bind_and_guard_matched_candidate (
256
+ this. clear_top_scope ( arm. scope ) ;
257
+ let binding_end = this. bind_and_guard_matched_candidate (
272
258
candidate,
273
259
arm. guard . clone ( ) ,
274
260
& fake_borrow_temps,
275
261
scrutinee_span,
262
+ region_scope,
276
263
) ;
277
- self . cfg . terminate (
264
+ this . cfg . terminate (
278
265
binding_end,
279
266
source_info,
280
267
TerminatorKind :: Goto { target : arm_block } ,
@@ -286,18 +273,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
286
273
this. source_scope = source_scope;
287
274
}
288
275
289
- for candidate in candidates {
290
- this. clear_top_scope ( arm. scope ) ;
291
- this. bind_and_guard_matched_candidate (
292
- candidate,
293
- arm. guard . clone ( ) ,
294
- arm_block,
295
- & fake_borrow_temps,
296
- scrutinee_span,
297
- region_scope,
298
- ) ;
299
- }
300
-
301
276
this. into ( destination, arm_block, body)
302
277
} )
303
278
} ) . collect ( ) ;
@@ -794,11 +769,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
794
769
/// the value, we will generate a branch to the appropriate
795
770
/// prebinding block.
796
771
///
797
- /// The return value is a list of "otherwise" blocks. These are
798
- /// points in execution where we found that *NONE* of the
799
- /// candidates apply. In principle, this means that the input
800
- /// list was not exhaustive, though at present we sometimes are
801
- /// not smart enough to recognize all exhaustive inputs.
772
+ /// If we find that *NONE* of the candidates apply, we branch to the
773
+ /// `otherwise_block`. In principle, this means that the input list was not
774
+ /// exhaustive, though at present we sometimes are not smart enough to
775
+ /// recognize all exhaustive inputs.
802
776
///
803
777
/// It might be surprising that the input can be inexhaustive.
804
778
/// Indeed, initially, it is not, because all matches are
@@ -812,13 +786,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
812
786
fn match_candidates < ' pat > (
813
787
& mut self ,
814
788
span : Span ,
789
+ start_block : & mut Option < BasicBlock > ,
790
+ otherwise_block : Option < BasicBlock > ,
815
791
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
816
- mut block : BasicBlock ,
817
792
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
818
- ) -> Vec < BasicBlock > {
793
+ ) {
819
794
debug ! (
820
- "matched_candidate(span={:?}, block={:?}, candidates={:?})" ,
821
- span, block, candidates
795
+ "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})" ,
796
+ span,
797
+ candidates,
798
+ start_block,
799
+ otherwise_block,
822
800
) ;
823
801
824
802
// Start by simplifying candidates. Once this process is complete, all
@@ -841,52 +819,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
841
819
) ;
842
820
let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
843
821
822
+ let block: BasicBlock ;
823
+
844
824
if !matched_candidates. is_empty ( ) {
845
- block = if let Some ( last_otherwise_block ) = self . select_matched_candidates (
825
+ let otherwise_block = self . select_matched_candidates (
846
826
matched_candidates,
847
- block ,
827
+ start_block ,
848
828
fake_borrows,
849
- ) {
850
- last_otherwise_block
829
+ ) ;
830
+
831
+ if let Some ( last_otherwise_block) = otherwise_block {
832
+ block = last_otherwise_block
851
833
} else {
852
834
// Any remaining candidates are unreachable.
853
835
if unmatched_candidates. is_empty ( ) {
854
- return Vec :: new ( ) ;
855
- } else {
856
- self . cfg . start_new_block ( )
836
+ return ;
857
837
}
838
+ block = self . cfg . start_new_block ( ) ;
858
839
} ;
840
+ } else {
841
+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
859
842
}
860
843
861
844
// If there are no candidates that still need testing, we're
862
845
// done. Since all matches are exhaustive, execution should
863
846
// never reach this point.
864
847
if unmatched_candidates. is_empty ( ) {
865
- return vec ! [ block] ;
848
+ let source_info = self . source_info ( span) ;
849
+ if let Some ( otherwise) = otherwise_block {
850
+ self . cfg . terminate (
851
+ block,
852
+ source_info,
853
+ TerminatorKind :: Goto { target : otherwise } ,
854
+ ) ;
855
+ } else {
856
+ self . cfg . terminate (
857
+ block,
858
+ source_info,
859
+ TerminatorKind :: Unreachable ,
860
+ )
861
+ }
862
+ return ;
866
863
}
867
864
868
- // Test candidates where possible .
869
- let ( otherwise , untested_candidates ) = self . test_candidates (
865
+ // Test for the remaining candidates .
866
+ self . test_candidates (
870
867
span,
871
868
unmatched_candidates,
872
869
block,
870
+ otherwise_block,
873
871
fake_borrows,
874
872
) ;
875
-
876
- // If the target candidates were exhaustive, then we are done.
877
- // But for borrowck continue build decision tree.
878
- if untested_candidates. is_empty ( ) {
879
- return otherwise;
880
- }
881
-
882
- // Otherwise, let's process those remaining candidates.
883
- let join_block = self . join_otherwise_blocks ( span, otherwise) ;
884
- self . match_candidates (
885
- span,
886
- untested_candidates,
887
- join_block,
888
- fake_borrows,
889
- )
890
873
}
891
874
892
875
/// Link up matched candidates. For example, if we have something like
@@ -910,7 +893,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
910
893
fn select_matched_candidates (
911
894
& mut self ,
912
895
matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
913
- block : BasicBlock ,
896
+ start_block : & mut Option < BasicBlock > ,
914
897
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
915
898
) -> Option < BasicBlock > {
916
899
debug_assert ! (
@@ -958,16 +941,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
958
941
= matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
959
942
960
943
let first_candidate = & reachable_candidates[ 0 ] ;
944
+ let first_prebinding_block = first_candidate. pre_binding_block ;
961
945
962
- let candidate_source_info = self . source_info ( first_candidate. span ) ;
963
-
964
- self . cfg . terminate (
965
- block,
966
- candidate_source_info,
967
- TerminatorKind :: Goto {
968
- target : first_candidate. pre_binding_block ,
969
- } ,
970
- ) ;
946
+ if let Some ( start_block) = * start_block {
947
+ let source_info = self . source_info ( first_candidate. span ) ;
948
+ self . cfg . terminate (
949
+ start_block,
950
+ source_info,
951
+ TerminatorKind :: Goto { target : first_prebinding_block } ,
952
+ ) ;
953
+ } else {
954
+ * start_block = Some ( first_prebinding_block) ;
955
+ }
971
956
972
957
for window in reachable_candidates. windows ( 2 ) {
973
958
if let [ first_candidate, second_candidate] = window {
@@ -1019,25 +1004,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1019
1004
}
1020
1005
}
1021
1006
1022
- fn join_otherwise_blocks ( & mut self , span : Span , mut otherwise : Vec < BasicBlock > ) -> BasicBlock {
1023
- let source_info = self . source_info ( span) ;
1024
- otherwise. sort ( ) ;
1025
- otherwise. dedup ( ) ; // variant switches can introduce duplicate target blocks
1026
- if otherwise. len ( ) == 1 {
1027
- otherwise[ 0 ]
1028
- } else {
1029
- let join_block = self . cfg . start_new_block ( ) ;
1030
- for block in otherwise {
1031
- self . cfg . terminate (
1032
- block,
1033
- source_info,
1034
- TerminatorKind :: Goto { target : join_block } ,
1035
- ) ;
1036
- }
1037
- join_block
1038
- }
1039
- }
1040
-
1041
1007
/// This is the most subtle part of the matching algorithm. At
1042
1008
/// this point, the input candidates have been fully simplified,
1043
1009
/// and so we know that all remaining match-pairs require some
@@ -1155,8 +1121,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1155
1121
span : Span ,
1156
1122
mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1157
1123
block : BasicBlock ,
1124
+ mut otherwise_block : Option < BasicBlock > ,
1158
1125
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1159
- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1126
+ ) {
1160
1127
// extract the match-pair from the highest priority candidate
1161
1128
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1162
1129
let mut test = self . test ( match_pair) ;
@@ -1210,9 +1177,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1210
1177
"match_candidates: test={:?} match_pair={:?}" ,
1211
1178
test, match_pair
1212
1179
) ;
1213
- let target_blocks = self . perform_test ( block, & match_place, & test) ;
1214
1180
let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
1215
- target_candidates. resize_with ( target_blocks . len ( ) , Default :: default) ;
1181
+ target_candidates. resize_with ( test . targets ( ) , Default :: default) ;
1216
1182
1217
1183
let total_candidate_count = candidates. len ( ) ;
1218
1184
@@ -1238,20 +1204,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1238
1204
// apply. Collect a list of blocks where control flow will
1239
1205
// branch if one of the `target_candidate` sets is not
1240
1206
// exhaustive.
1241
- let otherwise: Vec < _ > = target_blocks
1242
- . into_iter ( )
1243
- . zip ( target_candidates)
1244
- . flat_map ( |( target_block, mut target_candidates) | {
1207
+ if !candidates. is_empty ( ) {
1208
+ let remainder_start = & mut None ;
1209
+ self . match_candidates (
1210
+ span,
1211
+ remainder_start,
1212
+ otherwise_block,
1213
+ candidates,
1214
+ fake_borrows,
1215
+ ) ;
1216
+ otherwise_block = Some ( remainder_start. unwrap ( ) ) ;
1217
+ } ;
1218
+ let target_blocks: Vec < _ > = target_candidates. into_iter ( ) . map ( |mut candidates| {
1219
+ if candidates. len ( ) != 0 {
1220
+ let candidate_start = & mut None ;
1245
1221
self . match_candidates (
1246
1222
span,
1247
- & mut * target_candidates,
1248
- target_block,
1223
+ candidate_start,
1224
+ otherwise_block,
1225
+ & mut * candidates,
1249
1226
fake_borrows,
1250
- )
1251
- } )
1252
- . collect ( ) ;
1227
+ ) ;
1228
+ candidate_start. unwrap ( )
1229
+ } else {
1230
+ * otherwise_block. get_or_insert_with ( || {
1231
+ let unreachable = self . cfg . start_new_block ( ) ;
1232
+ let source_info = self . source_info ( span) ;
1233
+ self . cfg . terminate (
1234
+ unreachable,
1235
+ source_info,
1236
+ TerminatorKind :: Unreachable ,
1237
+ ) ;
1238
+ unreachable
1239
+ } )
1240
+ }
1241
+ } ) . collect ( ) ;
1253
1242
1254
- ( otherwise, candidates)
1243
+ self . perform_test (
1244
+ block,
1245
+ & match_place,
1246
+ & test,
1247
+ target_blocks,
1248
+ ) ;
1255
1249
}
1256
1250
1257
1251
// Determine the fake borrows that are needed to ensure that the place
@@ -1325,7 +1319,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1325
1319
fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
1326
1320
scrutinee_span : Span ,
1327
1321
region_scope : ( region:: Scope , SourceInfo ) ,
1328
- ) {
1329
1322
) -> BasicBlock {
1330
1323
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1331
1324
@@ -1347,10 +1340,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1347
1340
block,
1348
1341
fresh_block,
1349
1342
candidate. next_candidate_pre_binding_block ,
1350
- candidate_source_info,
1351
- ) ;
1343
+ candidate_source_info,
1344
+ ) ;
1352
1345
block = fresh_block;
1353
- self . ascribe_types ( block, & candidate. ascriptions ) ;
1346
+ self . ascribe_types ( block, & candidate. ascriptions ) ;
1354
1347
} else {
1355
1348
return block;
1356
1349
}
0 commit comments