@@ -206,33 +206,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206206 . flat_map ( |( _, candidates) | candidates)
207207 . collect :: < Vec < _ > > ( ) ;
208208
209+ let outer_source_info = self . source_info ( span) ;
210+
209211 // this will generate code to test scrutinee_place and
210212 // branch to the appropriate arm block
211- let otherwise = self . match_candidates (
213+ self . match_candidates (
212214 scrutinee_span,
215+ & mut Some ( block) ,
216+ None ,
213217 candidates,
214- block,
215218 & mut fake_borrows,
216219 ) ;
217220
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-
236221 // Step 4. Determine the fake borrows that are needed from the above
237222 // places. Create the required temporaries for them.
238223
@@ -247,8 +232,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
247232 let arm_source_info = self . source_info ( arm. span ) ;
248233 let region_scope = ( arm. scope , arm_source_info) ;
249234 self . in_scope ( region_scope, arm. lint_level , |this| {
250- let mut arm_block = this. cfg . start_new_block ( ) ;
251-
252235 let body = this. hir . mirror ( arm. body . clone ( ) ) ;
253236 let scope = this. declare_bindings (
254237 None ,
@@ -258,23 +241,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
258241 Some ( ( Some ( & scrutinee_place) , scrutinee_span) ) ,
259242 ) ;
260243
244+ let arm_block;
261245 if candidates. len ( ) == 1 {
262- arm_block = self . bind_and_guard_matched_candidate (
246+ arm_block = this . bind_and_guard_matched_candidate (
263247 candidates. pop ( ) . unwrap ( ) ,
264248 arm. guard . clone ( ) ,
265249 & fake_borrow_temps,
266250 scrutinee_span,
251+ region_scope,
267252 ) ;
268253 } else {
269- arm_block = self . cfg . start_new_block ( ) ;
254+ arm_block = this . cfg . start_new_block ( ) ;
270255 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 (
272258 candidate,
273259 arm. guard . clone ( ) ,
274260 & fake_borrow_temps,
275261 scrutinee_span,
262+ region_scope,
276263 ) ;
277- self . cfg . terminate (
264+ this . cfg . terminate (
278265 binding_end,
279266 source_info,
280267 TerminatorKind :: Goto { target : arm_block } ,
@@ -286,18 +273,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
286273 this. source_scope = source_scope;
287274 }
288275
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-
301276 this. into ( destination, arm_block, body)
302277 } )
303278 } ) . collect ( ) ;
@@ -792,11 +767,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
792767 /// the value, we will generate a branch to the appropriate
793768 /// prebinding block.
794769 ///
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.
800774 ///
801775 /// It might be surprising that the input can be inexhaustive.
802776 /// Indeed, initially, it is not, because all matches are
@@ -810,13 +784,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
810784 fn match_candidates < ' pat > (
811785 & mut self ,
812786 span : Span ,
787+ start_block : & mut Option < BasicBlock > ,
788+ otherwise_block : Option < BasicBlock > ,
813789 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
814- mut block : BasicBlock ,
815790 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
816- ) -> Vec < BasicBlock > {
791+ ) {
817792 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,
820798 ) ;
821799
822800 // Start by simplifying candidates. Once this process is complete, all
@@ -839,52 +817,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
839817 ) ;
840818 let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
841819
820+ let block: BasicBlock ;
821+
842822 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 (
844824 matched_candidates,
845- block ,
825+ start_block ,
846826 fake_borrows,
847- ) {
848- last_otherwise_block
827+ ) ;
828+
829+ if let Some ( last_otherwise_block) = otherwise_block {
830+ block = last_otherwise_block
849831 } else {
850832 // Any remaining candidates are unreachable.
851833 if unmatched_candidates. is_empty ( ) {
852- return Vec :: new ( ) ;
853- } else {
854- self . cfg . start_new_block ( )
834+ return ;
855835 }
836+ block = self . cfg . start_new_block ( ) ;
856837 } ;
838+ } else {
839+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
857840 }
858841
859842 // If there are no candidates that still need testing, we're
860843 // done. Since all matches are exhaustive, execution should
861844 // never reach this point.
862845 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 ;
864861 }
865862
866- // Test candidates where possible .
867- let ( otherwise , untested_candidates ) = self . test_candidates (
863+ // Test for the remaining candidates .
864+ self . test_candidates (
868865 span,
869866 unmatched_candidates,
870867 block,
868+ otherwise_block,
871869 fake_borrows,
872870 ) ;
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- )
888871 }
889872
890873 /// Link up matched candidates. For example, if we have something like
@@ -908,7 +891,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
908891 fn select_matched_candidates (
909892 & mut self ,
910893 matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
911- block : BasicBlock ,
894+ start_block : & mut Option < BasicBlock > ,
912895 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
913896 ) -> Option < BasicBlock > {
914897 debug_assert ! (
@@ -956,16 +939,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
956939 = matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
957940
958941 let first_candidate = & reachable_candidates[ 0 ] ;
942+ let first_prebinding_block = first_candidate. pre_binding_block ;
959943
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+ }
969954
970955 for window in reachable_candidates. windows ( 2 ) {
971956 if let [ first_candidate, second_candidate] = window {
@@ -1017,25 +1002,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
10171002 }
10181003 }
10191004
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-
10391005 /// This is the most subtle part of the matching algorithm. At
10401006 /// this point, the input candidates have been fully simplified,
10411007 /// and so we know that all remaining match-pairs require some
@@ -1153,8 +1119,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
11531119 span : Span ,
11541120 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
11551121 block : BasicBlock ,
1122+ mut otherwise_block : Option < BasicBlock > ,
11561123 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1157- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1124+ ) {
11581125 // extract the match-pair from the highest priority candidate
11591126 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
11601127 let mut test = self . test ( match_pair) ;
@@ -1208,9 +1175,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12081175 "match_candidates: test={:?} match_pair={:?}" ,
12091176 test, match_pair
12101177 ) ;
1211- let target_blocks = self . perform_test ( block, & match_place, & test) ;
12121178 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) ;
12141180
12151181 let total_candidate_count = candidates. len ( ) ;
12161182
@@ -1236,20 +1202,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12361202 // apply. Collect a list of blocks where control flow will
12371203 // branch if one of the `target_candidate` sets is not
12381204 // 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 ;
12431219 self . match_candidates (
12441220 span,
1245- & mut * target_candidates,
1246- target_block,
1221+ candidate_start,
1222+ otherwise_block,
1223+ & mut * candidates,
12471224 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 ( ) ;
12511240
1252- ( otherwise, candidates)
1241+ self . perform_test (
1242+ block,
1243+ & match_place,
1244+ & test,
1245+ target_blocks,
1246+ ) ;
12531247 }
12541248
12551249 // Determine the fake borrows that are needed to ensure that the place
@@ -1323,7 +1317,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13231317 fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
13241318 scrutinee_span : Span ,
13251319 region_scope : ( region:: Scope , SourceInfo ) ,
1326- ) {
13271320 ) -> BasicBlock {
13281321 debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
13291322
@@ -1345,10 +1338,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13451338 block,
13461339 fresh_block,
13471340 candidate. next_candidate_pre_binding_block ,
1348- candidate_source_info,
1349- ) ;
1341+ candidate_source_info,
1342+ ) ;
13501343 block = fresh_block;
1351- self . ascribe_types ( block, & candidate. ascriptions ) ;
1344+ self . ascribe_types ( block, & candidate. ascriptions ) ;
13521345 } else {
13531346 return block;
13541347 }
0 commit comments