@@ -1063,6 +1063,27 @@ pub(crate) struct Test<'tcx> {
10631063#[ derive( Copy , Clone , Debug ) ]
10641064pub ( crate ) struct ArmHasGuard ( pub ( crate ) bool ) ;
10651065
1066+ /// A single step in the match algorithm.
1067+ pub ( crate ) struct MatchAutomatonStep < ' a , ' c , ' pat , ' tcx > {
1068+ /// Perform this test...
1069+ test : Test < ' tcx > ,
1070+ /// ... on this place...
1071+ place : PlaceBuilder < ' tcx > ,
1072+ /// ... depending on the result, branch to one of these candidate lists...
1073+ target_candidates : Vec < Vec < & ' a mut Candidate < ' pat , ' tcx > > > ,
1074+ /// ... if it doesn't match, continue with these.
1075+ remaining_candidates : & ' a mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1076+ }
1077+
1078+ impl < ' b , ' c , ' pat , ' tcx > std:: fmt:: Debug for MatchAutomatonStep < ' b , ' c , ' pat , ' tcx > {
1079+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
1080+ f. debug_struct ( "MatchAutomatonStep" )
1081+ . field ( "test" , & self . test )
1082+ . field ( "place" , & self . place )
1083+ . finish ( )
1084+ }
1085+ }
1086+
10661087///////////////////////////////////////////////////////////////////////////
10671088// Main matching algorithm
10681089
@@ -1085,7 +1106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10851106 /// exhaustive in Rust. But during processing we sometimes divide
10861107 /// up the list of candidates and recurse with a non-exhaustive
10871108 /// list. This is important to keep the size of the generated code
1088- /// under control. See [`Builder::test_candidates `] for more details.
1109+ /// under control. See [`Builder::build_test_step `] for more details.
10891110 ///
10901111 /// If `fake_borrows` is `Some`, then places which need fake borrows
10911112 /// will be added to it.
@@ -1321,7 +1342,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13211342 }
13221343
13231344 /// Tests a candidate where there are only or-patterns left to test, or
1324- /// forwards to [Builder::test_candidates ].
1345+ /// forwards to [Builder::build_test_step ].
13251346 ///
13261347 /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
13271348 /// so:
@@ -1389,14 +1410,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13891410 match first_candidate. match_pairs [ 0 ] . pattern . kind {
13901411 PatKind :: Or { .. } => ( ) ,
13911412 _ => {
1392- self . test_candidates (
1393- span,
1394- scrutinee_span,
1395- candidates,
1396- block,
1397- otherwise_block,
1398- fake_borrows,
1399- ) ;
1413+ let step = self . build_test_step ( candidates, fake_borrows) ;
1414+ self . perform_test ( span, scrutinee_span, block, otherwise_block, fake_borrows, step) ;
14001415 return ;
14011416 }
14021417 }
@@ -1449,11 +1464,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14491464 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
14501465 ) {
14511466 debug ! ( "candidate={:#?}\n pats={:#?}" , candidate, pats) ;
1452- let mut or_candidates : Vec < _ > = pats
1467+ candidate . subcandidates = pats
14531468 . iter ( )
14541469 . map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
14551470 . collect ( ) ;
1456- let mut or_candidate_refs: Vec < _ > = or_candidates . iter_mut ( ) . collect ( ) ;
1471+ let mut or_candidate_refs: Vec < _ > = candidate . subcandidates . iter_mut ( ) . collect ( ) ;
14571472 let otherwise = if candidate. otherwise_block . is_some ( ) {
14581473 & mut candidate. otherwise_block
14591474 } else {
@@ -1467,7 +1482,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14671482 & mut or_candidate_refs,
14681483 fake_borrows,
14691484 ) ;
1470- candidate. subcandidates = or_candidates;
14711485 self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
14721486 }
14731487
@@ -1626,15 +1640,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16261640 /// In addition to avoiding exponential-time blowups, this algorithm
16271641 /// also has the nice property that each guard and arm is only generated
16281642 /// once.
1629- fn test_candidates < ' pat , ' b , ' c > (
1643+ fn build_test_step < ' pat , ' b , ' c > (
16301644 & mut self ,
1631- span : Span ,
1632- scrutinee_span : Span ,
16331645 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1634- block : BasicBlock ,
1635- otherwise_block : & mut Option < BasicBlock > ,
16361646 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1637- ) {
1647+ ) -> MatchAutomatonStep < ' b , ' c , ' pat , ' tcx > {
16381648 // extract the match-pair from the highest priority candidate
16391649 let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
16401650 let mut test = self . test ( match_pair) ;
@@ -1673,7 +1683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16731683 // those N possible outcomes, create a (initially empty)
16741684 // vector of candidates. Those are the candidates that still
16751685 // apply if the test has that particular outcome.
1676- debug ! ( "test_candidates : test={:?} match_pair={:?}" , test, match_pair) ;
1686+ debug ! ( "build_test_step : test={:?} match_pair={:?}" , test, match_pair) ;
16771687 let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
16781688 target_candidates. resize_with ( test. targets ( ) , Default :: default) ;
16791689
@@ -1699,59 +1709,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16991709 debug ! ( "tested_candidates: {}" , total_candidate_count - candidates. len( ) ) ;
17001710 debug ! ( "untested_candidates: {}" , candidates. len( ) ) ;
17011711
1702- // HACK(matthewjasper) This is a closure so that we can let the test
1703- // create its blocks before the rest of the match. This currently
1704- // improves the speed of llvm when optimizing long string literal
1705- // matches
1706- let make_target_blocks = move |this : & mut Self | -> Vec < BasicBlock > {
1707- // The block that we should branch to if none of the
1708- // `target_candidates` match. This is either the block where we
1709- // start matching the untested candidates if there are any,
1710- // otherwise it's the `otherwise_block`.
1711- let remainder_start = & mut None ;
1712- let remainder_start =
1713- if candidates. is_empty ( ) { & mut * otherwise_block } else { remainder_start } ;
1714-
1715- // For each outcome of test, process the candidates that still
1716- // apply. Collect a list of blocks where control flow will
1717- // branch if one of the `target_candidate` sets is not
1718- // exhaustive.
1719- let target_blocks: Vec < _ > = target_candidates
1720- . into_iter ( )
1721- . map ( |mut candidates| {
1722- if !candidates. is_empty ( ) {
1723- let candidate_start = this. cfg . start_new_block ( ) ;
1724- this. match_candidates (
1725- span,
1726- scrutinee_span,
1727- candidate_start,
1728- remainder_start,
1729- & mut * candidates,
1730- fake_borrows,
1731- ) ;
1732- candidate_start
1733- } else {
1734- * remainder_start. get_or_insert_with ( || this. cfg . start_new_block ( ) )
1735- }
1736- } )
1737- . collect ( ) ;
1738-
1739- if !candidates. is_empty ( ) {
1740- let remainder_start = remainder_start. unwrap_or_else ( || this. cfg . start_new_block ( ) ) ;
1741- this. match_candidates (
1742- span,
1743- scrutinee_span,
1744- remainder_start,
1745- otherwise_block,
1746- candidates,
1747- fake_borrows,
1748- ) ;
1749- } ;
1750-
1751- target_blocks
1752- } ;
1753-
1754- self . perform_test ( span, scrutinee_span, block, & match_place, & test, make_target_blocks) ;
1712+ MatchAutomatonStep {
1713+ test,
1714+ place : match_place,
1715+ remaining_candidates : candidates,
1716+ target_candidates,
1717+ }
17551718 }
17561719
17571720 /// Determine the fake borrows that are needed from a set of places that
0 commit comments