@@ -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 ( ) ;
@@ -792,11 +767,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
792
767
/// the value, we will generate a branch to the appropriate
793
768
/// prebinding block.
794
769
///
795
- /// The return value is a list of "otherwise" blocks. These are
796
- /// points in execution where we found that *NONE* of the
797
- /// candidates apply. In principle, this means that the input
798
- /// list was not exhaustive, though at present we sometimes are
799
- /// not smart enough to recognize all exhaustive inputs.
770
+ /// If we find that *NONE* of the candidates apply, we branch to the
771
+ /// `otherwise_block`. In principle, this means that the input list was not
772
+ /// exhaustive, though at present we sometimes are not smart enough to
773
+ /// recognize all exhaustive inputs.
800
774
///
801
775
/// It might be surprising that the input can be inexhaustive.
802
776
/// Indeed, initially, it is not, because all matches are
@@ -810,13 +784,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
810
784
fn match_candidates < ' pat > (
811
785
& mut self ,
812
786
span : Span ,
787
+ start_block : & mut Option < BasicBlock > ,
788
+ otherwise_block : Option < BasicBlock > ,
813
789
candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
814
- mut block : BasicBlock ,
815
790
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
816
- ) -> Vec < BasicBlock > {
791
+ ) {
817
792
debug ! (
818
- "matched_candidate(span={:?}, block={:?}, candidates={:?})" ,
819
- span, block, candidates
793
+ "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})" ,
794
+ span,
795
+ candidates,
796
+ start_block,
797
+ otherwise_block,
820
798
) ;
821
799
822
800
// Start by simplifying candidates. Once this process is complete, all
@@ -839,52 +817,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
839
817
) ;
840
818
let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
841
819
820
+ let block: BasicBlock ;
821
+
842
822
if !matched_candidates. is_empty ( ) {
843
- block = if let Some ( last_otherwise_block ) = self . select_matched_candidates (
823
+ let otherwise_block = self . select_matched_candidates (
844
824
matched_candidates,
845
- block ,
825
+ start_block ,
846
826
fake_borrows,
847
- ) {
848
- last_otherwise_block
827
+ ) ;
828
+
829
+ if let Some ( last_otherwise_block) = otherwise_block {
830
+ block = last_otherwise_block
849
831
} else {
850
832
// Any remaining candidates are unreachable.
851
833
if unmatched_candidates. is_empty ( ) {
852
- return Vec :: new ( ) ;
853
- } else {
854
- self . cfg . start_new_block ( )
834
+ return ;
855
835
}
836
+ block = self . cfg . start_new_block ( ) ;
856
837
} ;
838
+ } else {
839
+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
857
840
}
858
841
859
842
// If there are no candidates that still need testing, we're
860
843
// done. Since all matches are exhaustive, execution should
861
844
// never reach this point.
862
845
if unmatched_candidates. is_empty ( ) {
863
- return vec ! [ block] ;
846
+ let source_info = self . source_info ( span) ;
847
+ if let Some ( otherwise) = otherwise_block {
848
+ self . cfg . terminate (
849
+ block,
850
+ source_info,
851
+ TerminatorKind :: Goto { target : otherwise } ,
852
+ ) ;
853
+ } else {
854
+ self . cfg . terminate (
855
+ block,
856
+ source_info,
857
+ TerminatorKind :: Unreachable ,
858
+ )
859
+ }
860
+ return ;
864
861
}
865
862
866
- // Test candidates where possible .
867
- let ( otherwise , untested_candidates ) = self . test_candidates (
863
+ // Test for the remaining candidates .
864
+ self . test_candidates (
868
865
span,
869
866
unmatched_candidates,
870
867
block,
868
+ otherwise_block,
871
869
fake_borrows,
872
870
) ;
873
-
874
- // If the target candidates were exhaustive, then we are done.
875
- // But for borrowck continue build decision tree.
876
- if untested_candidates. is_empty ( ) {
877
- return otherwise;
878
- }
879
-
880
- // Otherwise, let's process those remaining candidates.
881
- let join_block = self . join_otherwise_blocks ( span, otherwise) ;
882
- self . match_candidates (
883
- span,
884
- untested_candidates,
885
- join_block,
886
- fake_borrows,
887
- )
888
871
}
889
872
890
873
/// Link up matched candidates. For example, if we have something like
@@ -908,7 +891,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
908
891
fn select_matched_candidates (
909
892
& mut self ,
910
893
matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
911
- block : BasicBlock ,
894
+ start_block : & mut Option < BasicBlock > ,
912
895
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
913
896
) -> Option < BasicBlock > {
914
897
debug_assert ! (
@@ -956,16 +939,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
956
939
= matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
957
940
958
941
let first_candidate = & reachable_candidates[ 0 ] ;
942
+ let first_prebinding_block = first_candidate. pre_binding_block ;
959
943
960
- let candidate_source_info = self . source_info ( first_candidate. span ) ;
961
-
962
- self . cfg . terminate (
963
- block,
964
- candidate_source_info,
965
- TerminatorKind :: Goto {
966
- target : first_candidate. pre_binding_block ,
967
- } ,
968
- ) ;
944
+ if let Some ( start_block) = * start_block {
945
+ let source_info = self . source_info ( first_candidate. span ) ;
946
+ self . cfg . terminate (
947
+ start_block,
948
+ source_info,
949
+ TerminatorKind :: Goto { target : first_prebinding_block } ,
950
+ ) ;
951
+ } else {
952
+ * start_block = Some ( first_prebinding_block) ;
953
+ }
969
954
970
955
for window in reachable_candidates. windows ( 2 ) {
971
956
if let [ first_candidate, second_candidate] = window {
@@ -1017,25 +1002,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1017
1002
}
1018
1003
}
1019
1004
1020
- fn join_otherwise_blocks ( & mut self , span : Span , mut otherwise : Vec < BasicBlock > ) -> BasicBlock {
1021
- let source_info = self . source_info ( span) ;
1022
- otherwise. sort ( ) ;
1023
- otherwise. dedup ( ) ; // variant switches can introduce duplicate target blocks
1024
- if otherwise. len ( ) == 1 {
1025
- otherwise[ 0 ]
1026
- } else {
1027
- let join_block = self . cfg . start_new_block ( ) ;
1028
- for block in otherwise {
1029
- self . cfg . terminate (
1030
- block,
1031
- source_info,
1032
- TerminatorKind :: Goto { target : join_block } ,
1033
- ) ;
1034
- }
1035
- join_block
1036
- }
1037
- }
1038
-
1039
1005
/// This is the most subtle part of the matching algorithm. At
1040
1006
/// this point, the input candidates have been fully simplified,
1041
1007
/// and so we know that all remaining match-pairs require some
@@ -1153,8 +1119,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1153
1119
span : Span ,
1154
1120
mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1155
1121
block : BasicBlock ,
1122
+ mut otherwise_block : Option < BasicBlock > ,
1156
1123
fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1157
- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1124
+ ) {
1158
1125
// extract the match-pair from the highest priority candidate
1159
1126
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1160
1127
let mut test = self . test ( match_pair) ;
@@ -1208,9 +1175,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1208
1175
"match_candidates: test={:?} match_pair={:?}" ,
1209
1176
test, match_pair
1210
1177
) ;
1211
- let target_blocks = self . perform_test ( block, & match_place, & test) ;
1212
1178
let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
1213
- target_candidates. resize_with ( target_blocks . len ( ) , Default :: default) ;
1179
+ target_candidates. resize_with ( test . targets ( ) , Default :: default) ;
1214
1180
1215
1181
let total_candidate_count = candidates. len ( ) ;
1216
1182
@@ -1236,20 +1202,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1236
1202
// apply. Collect a list of blocks where control flow will
1237
1203
// branch if one of the `target_candidate` sets is not
1238
1204
// exhaustive.
1239
- let otherwise: Vec < _ > = target_blocks
1240
- . into_iter ( )
1241
- . zip ( target_candidates)
1242
- . flat_map ( |( target_block, mut target_candidates) | {
1205
+ if !candidates. is_empty ( ) {
1206
+ let remainder_start = & mut None ;
1207
+ self . match_candidates (
1208
+ span,
1209
+ remainder_start,
1210
+ otherwise_block,
1211
+ candidates,
1212
+ fake_borrows,
1213
+ ) ;
1214
+ otherwise_block = Some ( remainder_start. unwrap ( ) ) ;
1215
+ } ;
1216
+ let target_blocks: Vec < _ > = target_candidates. into_iter ( ) . map ( |mut candidates| {
1217
+ if candidates. len ( ) != 0 {
1218
+ let candidate_start = & mut None ;
1243
1219
self . match_candidates (
1244
1220
span,
1245
- & mut * target_candidates,
1246
- target_block,
1221
+ candidate_start,
1222
+ otherwise_block,
1223
+ & mut * candidates,
1247
1224
fake_borrows,
1248
- )
1249
- } )
1250
- . collect ( ) ;
1225
+ ) ;
1226
+ candidate_start. unwrap ( )
1227
+ } else {
1228
+ * otherwise_block. get_or_insert_with ( || {
1229
+ let unreachable = self . cfg . start_new_block ( ) ;
1230
+ let source_info = self . source_info ( span) ;
1231
+ self . cfg . terminate (
1232
+ unreachable,
1233
+ source_info,
1234
+ TerminatorKind :: Unreachable ,
1235
+ ) ;
1236
+ unreachable
1237
+ } )
1238
+ }
1239
+ } ) . collect ( ) ;
1251
1240
1252
- ( otherwise, candidates)
1241
+ self . perform_test (
1242
+ block,
1243
+ & match_place,
1244
+ & test,
1245
+ target_blocks,
1246
+ ) ;
1253
1247
}
1254
1248
1255
1249
// Determine the fake borrows that are needed to ensure that the place
@@ -1323,7 +1317,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1323
1317
fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
1324
1318
scrutinee_span : Span ,
1325
1319
region_scope : ( region:: Scope , SourceInfo ) ,
1326
- ) {
1327
1320
) -> BasicBlock {
1328
1321
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1329
1322
@@ -1345,10 +1338,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1345
1338
block,
1346
1339
fresh_block,
1347
1340
candidate. next_candidate_pre_binding_block ,
1348
- candidate_source_info,
1349
- ) ;
1341
+ candidate_source_info,
1342
+ ) ;
1350
1343
block = fresh_block;
1351
- self . ascribe_types ( block, & candidate. ascriptions ) ;
1344
+ self . ascribe_types ( block, & candidate. ascriptions ) ;
1352
1345
} else {
1353
1346
return block;
1354
1347
}
0 commit comments