@@ -205,33 +205,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
205205 . flat_map ( |( _, candidates) | candidates)
206206 . collect :: < Vec < _ > > ( ) ;
207207
208+ let outer_source_info = self . source_info ( span) ;
209+
208210 // this will generate code to test scrutinee_place and
209211 // branch to the appropriate arm block
210- let otherwise = self . match_candidates (
212+ self . match_candidates (
211213 scrutinee_span,
214+ & mut Some ( block) ,
215+ None ,
212216 candidates,
213- block,
214217 & mut fake_borrows,
215218 ) ;
216219
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-
235220 // Step 4. Determine the fake borrows that are needed from the above
236221 // places. Create the required temporaries for them.
237222
@@ -264,19 +249,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
264249 ) ;
265250 } else {
266251 arm_block = self . cfg . start_new_block ( ) ;
267- for candidate in candidates {
252+ for candidate in candidates {
268253 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+ ) ;
274259 self . cfg . terminate (
275260 binding_end,
276261 source_info,
277262 TerminatorKind :: Goto { target : arm_block } ,
278263 ) ;
279- }
264+ }
280265 }
281266
282267 if let Some ( source_scope) = scope {
@@ -793,11 +778,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
793778 /// the value, we will generate a branch to the appropriate
794779 /// prebinding block.
795780 ///
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.
801785 ///
802786 /// It might be surprising that the input can be inexhaustive.
803787 /// Indeed, initially, it is not, because all matches are
@@ -811,13 +795,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
811795 fn match_candidates < ' pat > (
812796 & mut self ,
813797 span : Span ,
798+ start_block : & mut Option < BasicBlock > ,
799+ otherwise_block : Option < BasicBlock > ,
814800 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
815- mut block : BasicBlock ,
816801 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
817- ) -> Vec < BasicBlock > {
802+ ) {
818803 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,
821809 ) ;
822810
823811 // Start by simplifying candidates. Once this process is complete, all
@@ -840,52 +828,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
840828 ) ;
841829 let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
842830
831+ let block: BasicBlock ;
832+
843833 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 (
845835 matched_candidates,
846- block ,
836+ start_block ,
847837 fake_borrows,
848- ) {
849- last_otherwise_block
838+ ) ;
839+
840+ if let Some ( last_otherwise_block) = otherwise_block {
841+ block = last_otherwise_block
850842 } else {
851843 // Any remaining candidates are unreachable.
852844 if unmatched_candidates. is_empty ( ) {
853- return Vec :: new ( ) ;
854- } else {
855- self . cfg . start_new_block ( )
845+ return ;
856846 }
847+ block = self . cfg . start_new_block ( ) ;
857848 } ;
849+ } else {
850+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
858851 }
859852
860853 // If there are no candidates that still need testing, we're
861854 // done. Since all matches are exhaustive, execution should
862855 // never reach this point.
863856 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 ;
865872 }
866873
867- // Test candidates where possible .
868- let ( otherwise , untested_candidates ) = self . test_candidates (
874+ // Test for the remaining candidates .
875+ self . test_candidates (
869876 span,
870877 unmatched_candidates,
871878 block,
879+ otherwise_block,
872880 fake_borrows,
873881 ) ;
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- )
889882 }
890883
891884 /// Link up matched candidates. For example, if we have something like
@@ -909,7 +902,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
909902 fn select_matched_candidates (
910903 & mut self ,
911904 matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
912- block : BasicBlock ,
905+ start_block : & mut Option < BasicBlock > ,
913906 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
914907 ) -> Option < BasicBlock > {
915908 debug_assert ! (
@@ -957,16 +950,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
957950 = matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
958951
959952 let first_candidate = & reachable_candidates[ 0 ] ;
953+ let first_prebinding_block = first_candidate. pre_binding_block ;
960954
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+ }
970965
971966 for window in reachable_candidates. windows ( 2 ) {
972967 if let [ first_candidate, second_candidate] = window {
@@ -1018,25 +1013,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
10181013 }
10191014 }
10201015
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-
10401016 /// This is the most subtle part of the matching algorithm. At
10411017 /// this point, the input candidates have been fully simplified,
10421018 /// and so we know that all remaining match-pairs require some
@@ -1154,8 +1130,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
11541130 span : Span ,
11551131 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
11561132 block : BasicBlock ,
1133+ mut otherwise_block : Option < BasicBlock > ,
11571134 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1158- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1135+ ) {
11591136 // extract the match-pair from the highest priority candidate
11601137 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
11611138 let mut test = self . test ( match_pair) ;
@@ -1209,9 +1186,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12091186 "match_candidates: test={:?} match_pair={:?}" ,
12101187 test, match_pair
12111188 ) ;
1212- let target_blocks = self . perform_test ( block, & match_place, & test) ;
12131189 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) ;
12151191
12161192 let total_candidate_count = candidates. len ( ) ;
12171193
@@ -1237,20 +1213,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12371213 // apply. Collect a list of blocks where control flow will
12381214 // branch if one of the `target_candidate` sets is not
12391215 // 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 ;
12441230 self . match_candidates (
12451231 span,
1246- & mut * target_candidates,
1247- target_block,
1232+ candidate_start,
1233+ otherwise_block,
1234+ & mut * candidates,
12481235 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 ( ) ;
12521251
1253- ( otherwise, candidates)
1252+ self . perform_test (
1253+ block,
1254+ & match_place,
1255+ & test,
1256+ target_blocks,
1257+ ) ;
12541258 }
12551259
12561260 // Determine the fake borrows that are needed to ensure that the place
@@ -1344,10 +1348,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13441348 block,
13451349 fresh_block,
13461350 candidate. next_candidate_pre_binding_block ,
1347- candidate_source_info,
1348- ) ;
1351+ candidate_source_info,
1352+ ) ;
13491353 block = fresh_block;
1350- self . ascribe_types ( block, & candidate. ascriptions ) ;
1354+ self . ascribe_types ( block, & candidate. ascriptions ) ;
13511355 } else {
13521356 return block;
13531357 }
0 commit comments