@@ -1364,108 +1364,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1364
1364
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1365
1365
/// code size at the expense of non-optimal code paths.
1366
1366
#[ instrument( skip( self ) , level = "debug" ) ]
1367
- fn match_candidates < ' pat > (
1367
+ fn match_candidates (
1368
1368
& mut self ,
1369
1369
span : Span ,
1370
1370
scrutinee_span : Span ,
1371
1371
start_block : BasicBlock ,
1372
1372
otherwise_block : BasicBlock ,
1373
- candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1373
+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1374
1374
) {
1375
- // We process or-patterns here. If any candidate starts with an or-pattern, we have to
1376
- // expand the or-pattern before we can proceed further.
1377
- //
1378
- // We can't expand them freely however. The rule is: if the candidate has an or-pattern as
1379
- // its only remaining match pair, we can expand it freely. If it has other match pairs, we
1380
- // can expand it but we can't process more candidates after it.
1381
- //
1382
- // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
1383
- // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
1384
- // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
1385
- // set of candidates, when we reach the block that tests `false` we don't know whether we
1386
- // came from `1` or `2`, hence we can't know where to branch on failure.
1387
- // ```ignore(illustrative)
1388
- // match (1, true) {
1389
- // (1 | 2, false) => {},
1390
- // (2, _) => {},
1391
- // _ => {}
1392
- // }
1393
- // ```
1394
- //
1395
- // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1396
- // and process both halves separately.
1397
- let mut expand_until = 0 ;
1398
- for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1399
- if matches ! (
1375
+ // If any candidate starts with an or-pattern, we have to expand the or-pattern before we
1376
+ // can proceed further.
1377
+ let expand_ors = candidates. iter ( ) . any ( |candidate| {
1378
+ matches ! (
1400
1379
& * candidate. match_pairs,
1401
1380
[ MatchPair { test_case: TestCase :: Or { .. } , .. } , ..]
1402
- ) {
1403
- expand_until = i + 1 ;
1404
- if candidate. match_pairs . len ( ) > 1 {
1405
- break ;
1406
- }
1407
- }
1408
- if expand_until != 0 {
1409
- expand_until = i + 1 ;
1410
- }
1411
- }
1412
- let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1413
-
1381
+ )
1382
+ } ) ;
1414
1383
ensure_sufficient_stack ( || {
1415
- if candidates_to_expand . is_empty ( ) {
1384
+ if !expand_ors {
1416
1385
// No candidates start with an or-pattern, we can continue.
1417
1386
self . match_expanded_candidates (
1418
1387
span,
1419
1388
scrutinee_span,
1420
1389
start_block,
1421
1390
otherwise_block,
1422
- remaining_candidates ,
1391
+ candidates ,
1423
1392
) ;
1424
1393
} else {
1425
- // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1426
- let mut expanded_candidates = Vec :: new ( ) ;
1427
- for candidate in candidates_to_expand. iter_mut ( ) {
1428
- if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] =
1429
- & * candidate. match_pairs
1430
- {
1431
- let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1432
- // Expand the or-pattern into subcandidates.
1433
- self . create_or_subcandidates ( candidate, or_match_pair) ;
1434
- // Collect the newly created subcandidates.
1435
- for subcandidate in candidate. subcandidates . iter_mut ( ) {
1436
- expanded_candidates. push ( subcandidate) ;
1437
- }
1438
- } else {
1439
- expanded_candidates. push ( candidate) ;
1440
- }
1441
- }
1442
-
1443
- // Process the expanded candidates.
1444
- let remainder_start = self . cfg . start_new_block ( ) ;
1445
- // There might be new or-patterns obtained from expanding the old ones, so we call
1446
- // `match_candidates` again.
1447
- self . match_candidates (
1394
+ self . expand_and_match_or_candidates (
1448
1395
span,
1449
1396
scrutinee_span,
1450
1397
start_block,
1451
- remainder_start,
1452
- expanded_candidates. as_mut_slice ( ) ,
1453
- ) ;
1454
-
1455
- // Simplify subcandidates and process any leftover match pairs.
1456
- for candidate in candidates_to_expand {
1457
- if !candidate. subcandidates . is_empty ( ) {
1458
- self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1459
- }
1460
- }
1461
-
1462
- // Process the remaining candidates.
1463
- self . match_candidates (
1464
- span,
1465
- scrutinee_span,
1466
- remainder_start,
1467
1398
otherwise_block,
1468
- remaining_candidates ,
1399
+ candidates ,
1469
1400
) ;
1470
1401
}
1471
1402
} ) ;
@@ -1561,6 +1492,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1561
1492
otherwise_block
1562
1493
}
1563
1494
1495
+ /// Takes a list of candidates such that some of the candidates' first match pairs are
1496
+ /// or-patterns, expands as many or-patterns as possible, and processes the resulting
1497
+ /// candidates.
1498
+ fn expand_and_match_or_candidates (
1499
+ & mut self ,
1500
+ span : Span ,
1501
+ scrutinee_span : Span ,
1502
+ start_block : BasicBlock ,
1503
+ otherwise_block : BasicBlock ,
1504
+ candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1505
+ ) {
1506
+ // We can't expand or-patterns freely. The rule is: if the candidate has an
1507
+ // or-pattern as its only remaining match pair, we can expand it freely. If it has
1508
+ // other match pairs, we can expand it but we can't process more candidates after
1509
+ // it.
1510
+ //
1511
+ // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the
1512
+ // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it
1513
+ // so the `1` and `2` cases branch to a same block (which then tests `false`). If we
1514
+ // took `(2, _)` in the same set of candidates, when we reach the block that tests
1515
+ // `false` we don't know whether we came from `1` or `2`, hence we can't know where
1516
+ // to branch on failure.
1517
+ //
1518
+ // ```ignore(illustrative)
1519
+ // match (1, true) {
1520
+ // (1 | 2, false) => {},
1521
+ // (2, _) => {},
1522
+ // _ => {}
1523
+ // }
1524
+ // ```
1525
+ //
1526
+ // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
1527
+ // and process the rest separately.
1528
+ let mut expand_until = 0 ;
1529
+ for ( i, candidate) in candidates. iter ( ) . enumerate ( ) {
1530
+ expand_until = i + 1 ;
1531
+ if candidate. match_pairs . len ( ) > 1
1532
+ && matches ! ( & candidate. match_pairs[ 0 ] . test_case, TestCase :: Or { .. } )
1533
+ {
1534
+ // The candidate has an or-pattern as well as more match pairs: we must
1535
+ // split the candidates list here.
1536
+ break ;
1537
+ }
1538
+ }
1539
+ let ( candidates_to_expand, remaining_candidates) = candidates. split_at_mut ( expand_until) ;
1540
+
1541
+ // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
1542
+ let mut expanded_candidates = Vec :: new ( ) ;
1543
+ for candidate in candidates_to_expand. iter_mut ( ) {
1544
+ if let [ MatchPair { test_case : TestCase :: Or { .. } , .. } , ..] = & * candidate. match_pairs
1545
+ {
1546
+ let or_match_pair = candidate. match_pairs . remove ( 0 ) ;
1547
+ // Expand the or-pattern into subcandidates.
1548
+ self . create_or_subcandidates ( candidate, or_match_pair) ;
1549
+ // Collect the newly created subcandidates.
1550
+ for subcandidate in candidate. subcandidates . iter_mut ( ) {
1551
+ expanded_candidates. push ( subcandidate) ;
1552
+ }
1553
+ } else {
1554
+ expanded_candidates. push ( candidate) ;
1555
+ }
1556
+ }
1557
+
1558
+ // Process the expanded candidates.
1559
+ let remainder_start = self . cfg . start_new_block ( ) ;
1560
+ // There might be new or-patterns obtained from expanding the old ones, so we call
1561
+ // `match_candidates` again.
1562
+ self . match_candidates (
1563
+ span,
1564
+ scrutinee_span,
1565
+ start_block,
1566
+ remainder_start,
1567
+ expanded_candidates. as_mut_slice ( ) ,
1568
+ ) ;
1569
+
1570
+ // Simplify subcandidates and process any leftover match pairs.
1571
+ for candidate in candidates_to_expand {
1572
+ if !candidate. subcandidates . is_empty ( ) {
1573
+ self . finalize_or_candidate ( span, scrutinee_span, candidate) ;
1574
+ }
1575
+ }
1576
+
1577
+ // Process the remaining candidates.
1578
+ self . match_candidates (
1579
+ span,
1580
+ scrutinee_span,
1581
+ remainder_start,
1582
+ otherwise_block,
1583
+ remaining_candidates,
1584
+ ) ;
1585
+ }
1586
+
1564
1587
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
1565
1588
/// subcandidate. Any candidate that has been expanded that way should be passed to
1566
1589
/// `finalize_or_candidate` after its subcandidates have been processed.
0 commit comments