@@ -1063,6 +1063,27 @@ pub(crate) struct Test<'tcx> {
1063
1063
#[ derive( Copy , Clone , Debug ) ]
1064
1064
pub ( crate ) struct ArmHasGuard ( pub ( crate ) bool ) ;
1065
1065
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
+
1066
1087
///////////////////////////////////////////////////////////////////////////
1067
1088
// Main matching algorithm
1068
1089
@@ -1085,7 +1106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1085
1106
/// exhaustive in Rust. But during processing we sometimes divide
1086
1107
/// up the list of candidates and recurse with a non-exhaustive
1087
1108
/// 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.
1089
1110
///
1090
1111
/// If `fake_borrows` is `Some`, then places which need fake borrows
1091
1112
/// will be added to it.
@@ -1321,7 +1342,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1321
1342
}
1322
1343
1323
1344
/// 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 ].
1325
1346
///
1326
1347
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
1327
1348
/// so:
@@ -1389,14 +1410,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1389
1410
match first_candidate. match_pairs [ 0 ] . pattern . kind {
1390
1411
PatKind :: Or { .. } => ( ) ,
1391
1412
_ => {
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) ;
1400
1415
return ;
1401
1416
}
1402
1417
}
@@ -1449,11 +1464,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1449
1464
fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1450
1465
) {
1451
1466
debug ! ( "candidate={:#?}\n pats={:#?}" , candidate, pats) ;
1452
- let mut or_candidates : Vec < _ > = pats
1467
+ candidate . subcandidates = pats
1453
1468
. iter ( )
1454
1469
. map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
1455
1470
. 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 ( ) ;
1457
1472
let otherwise = if candidate. otherwise_block . is_some ( ) {
1458
1473
& mut candidate. otherwise_block
1459
1474
} else {
@@ -1467,7 +1482,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1467
1482
& mut or_candidate_refs,
1468
1483
fake_borrows,
1469
1484
) ;
1470
- candidate. subcandidates = or_candidates;
1471
1485
self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
1472
1486
}
1473
1487
@@ -1626,15 +1640,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1626
1640
/// In addition to avoiding exponential-time blowups, this algorithm
1627
1641
/// also has the nice property that each guard and arm is only generated
1628
1642
/// once.
1629
- fn test_candidates < ' pat , ' b , ' c > (
1643
+ fn build_test_step < ' pat , ' b , ' c > (
1630
1644
& mut self ,
1631
- span : Span ,
1632
- scrutinee_span : Span ,
1633
1645
mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1634
- block : BasicBlock ,
1635
- otherwise_block : & mut Option < BasicBlock > ,
1636
1646
fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1637
- ) {
1647
+ ) -> MatchAutomatonStep < ' b , ' c , ' pat , ' tcx > {
1638
1648
// extract the match-pair from the highest priority candidate
1639
1649
let match_pair = & candidates. first ( ) . unwrap ( ) . match_pairs [ 0 ] ;
1640
1650
let mut test = self . test ( match_pair) ;
@@ -1673,7 +1683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1673
1683
// those N possible outcomes, create a (initially empty)
1674
1684
// vector of candidates. Those are the candidates that still
1675
1685
// 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) ;
1677
1687
let mut target_candidates: Vec < Vec < & mut Candidate < ' pat , ' tcx > > > = vec ! [ ] ;
1678
1688
target_candidates. resize_with ( test. targets ( ) , Default :: default) ;
1679
1689
@@ -1699,59 +1709,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1699
1709
debug ! ( "tested_candidates: {}" , total_candidate_count - candidates. len( ) ) ;
1700
1710
debug ! ( "untested_candidates: {}" , candidates. len( ) ) ;
1701
1711
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
+ }
1755
1718
}
1756
1719
1757
1720
/// Determine the fake borrows that are needed from a set of places that
0 commit comments