@@ -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 ( ) ;
@@ -794,11 +769,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
794769 /// the value, we will generate a branch to the appropriate
795770 /// prebinding block.
796771 ///
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.
802776 ///
803777 /// It might be surprising that the input can be inexhaustive.
804778 /// Indeed, initially, it is not, because all matches are
@@ -812,13 +786,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
812786 fn match_candidates < ' pat > (
813787 & mut self ,
814788 span : Span ,
789+ start_block : & mut Option < BasicBlock > ,
790+ otherwise_block : Option < BasicBlock > ,
815791 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
816- mut block : BasicBlock ,
817792 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
818- ) -> Vec < BasicBlock > {
793+ ) {
819794 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,
822800 ) ;
823801
824802 // Start by simplifying candidates. Once this process is complete, all
@@ -841,52 +819,57 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
841819 ) ;
842820 let ( matched_candidates, unmatched_candidates) = candidates. split_at_mut ( fully_matched) ;
843821
822+ let block: BasicBlock ;
823+
844824 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 (
846826 matched_candidates,
847- block ,
827+ start_block ,
848828 fake_borrows,
849- ) {
850- last_otherwise_block
829+ ) ;
830+
831+ if let Some ( last_otherwise_block) = otherwise_block {
832+ block = last_otherwise_block
851833 } else {
852834 // Any remaining candidates are unreachable.
853835 if unmatched_candidates. is_empty ( ) {
854- return Vec :: new ( ) ;
855- } else {
856- self . cfg . start_new_block ( )
836+ return ;
857837 }
838+ block = self . cfg . start_new_block ( ) ;
858839 } ;
840+ } else {
841+ block = * start_block. get_or_insert_with ( || self . cfg . start_new_block ( ) ) ;
859842 }
860843
861844 // If there are no candidates that still need testing, we're
862845 // done. Since all matches are exhaustive, execution should
863846 // never reach this point.
864847 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 ;
866863 }
867864
868- // Test candidates where possible .
869- let ( otherwise , untested_candidates ) = self . test_candidates (
865+ // Test for the remaining candidates .
866+ self . test_candidates (
870867 span,
871868 unmatched_candidates,
872869 block,
870+ otherwise_block,
873871 fake_borrows,
874872 ) ;
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- )
890873 }
891874
892875 /// Link up matched candidates. For example, if we have something like
@@ -910,7 +893,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
910893 fn select_matched_candidates (
911894 & mut self ,
912895 matched_candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
913- block : BasicBlock ,
896+ start_block : & mut Option < BasicBlock > ,
914897 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
915898 ) -> Option < BasicBlock > {
916899 debug_assert ! (
@@ -958,16 +941,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
958941 = matched_candidates. split_at_mut ( fully_matched_with_guard + 1 ) ;
959942
960943 let first_candidate = & reachable_candidates[ 0 ] ;
944+ let first_prebinding_block = first_candidate. pre_binding_block ;
961945
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+ }
971956
972957 for window in reachable_candidates. windows ( 2 ) {
973958 if let [ first_candidate, second_candidate] = window {
@@ -1019,25 +1004,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
10191004 }
10201005 }
10211006
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-
10411007 /// This is the most subtle part of the matching algorithm. At
10421008 /// this point, the input candidates have been fully simplified,
10431009 /// and so we know that all remaining match-pairs require some
@@ -1155,8 +1121,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
11551121 span : Span ,
11561122 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
11571123 block : BasicBlock ,
1124+ mut otherwise_block : Option < BasicBlock > ,
11581125 fake_borrows : & mut Option < FxHashSet < Place < ' tcx > > > ,
1159- ) -> ( Vec < BasicBlock > , & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ) {
1126+ ) {
11601127 // extract the match-pair from the highest priority candidate
11611128 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
11621129 let mut test = self . test ( match_pair) ;
@@ -1210,9 +1177,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12101177 "match_candidates: test={:?} match_pair={:?}" ,
12111178 test, match_pair
12121179 ) ;
1213- let target_blocks = self . perform_test ( block, & match_place, & test) ;
12141180 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) ;
12161182
12171183 let total_candidate_count = candidates. len ( ) ;
12181184
@@ -1238,20 +1204,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
12381204 // apply. Collect a list of blocks where control flow will
12391205 // branch if one of the `target_candidate` sets is not
12401206 // 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 ;
12451221 self . match_candidates (
12461222 span,
1247- & mut * target_candidates,
1248- target_block,
1223+ candidate_start,
1224+ otherwise_block,
1225+ & mut * candidates,
12491226 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 ( ) ;
12531242
1254- ( otherwise, candidates)
1243+ self . perform_test (
1244+ block,
1245+ & match_place,
1246+ & test,
1247+ target_blocks,
1248+ ) ;
12551249 }
12561250
12571251 // Determine the fake borrows that are needed to ensure that the place
@@ -1325,7 +1319,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13251319 fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
13261320 scrutinee_span : Span ,
13271321 region_scope : ( region:: Scope , SourceInfo ) ,
1328- ) {
13291322 ) -> BasicBlock {
13301323 debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
13311324
@@ -1347,10 +1340,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
13471340 block,
13481341 fresh_block,
13491342 candidate. next_candidate_pre_binding_block ,
1350- candidate_source_info,
1351- ) ;
1343+ candidate_source_info,
1344+ ) ;
13521345 block = fresh_block;
1353- self . ascribe_types ( block, & candidate. ascriptions ) ;
1346+ self . ascribe_types ( block, & candidate. ascriptions ) ;
13541347 } else {
13551348 return block;
13561349 }
0 commit comments