@@ -1052,7 +1052,7 @@ struct Ascription<'tcx> {
1052
1052
variance : ty:: Variance ,
1053
1053
}
1054
1054
1055
- #[ derive( Debug ) ]
1055
+ #[ derive( Debug , Clone ) ]
1056
1056
pub ( crate ) struct MatchPair < ' pat , ' tcx > {
1057
1057
// This place...
1058
1058
place : PlaceBuilder < ' tcx > ,
@@ -1408,69 +1408,85 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1408
1408
span : Span ,
1409
1409
scrutinee_span : Span ,
1410
1410
candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
1411
- block : BasicBlock ,
1411
+ start_block : BasicBlock ,
1412
1412
otherwise_block : BasicBlock ,
1413
1413
fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
1414
1414
) {
1415
1415
let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
1416
-
1417
- // All of the or-patterns have been sorted to the end, so if the first
1418
- // pattern is an or-pattern we only have or-patterns.
1419
- match first_candidate. match_pairs [ 0 ] . pattern . kind {
1420
- PatKind :: Or { .. } => ( ) ,
1421
- _ => {
1422
- self . test_candidates (
1423
- span,
1424
- scrutinee_span,
1425
- candidates,
1426
- block,
1427
- otherwise_block,
1428
- fake_borrows,
1429
- ) ;
1430
- return ;
1431
- }
1416
+ assert ! ( first_candidate. subcandidates. is_empty( ) ) ;
1417
+ if !matches ! ( first_candidate. match_pairs[ 0 ] . pattern. kind, PatKind :: Or { .. } ) {
1418
+ self . test_candidates (
1419
+ span,
1420
+ scrutinee_span,
1421
+ candidates,
1422
+ start_block,
1423
+ otherwise_block,
1424
+ fake_borrows,
1425
+ ) ;
1426
+ return ;
1432
1427
}
1433
1428
1434
1429
let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
1435
- first_candidate. pre_binding_block = Some ( block) ;
1430
+ let ( first_match_pair, remaining_match_pairs) = match_pairs. split_first ( ) . unwrap ( ) ;
1431
+ let PatKind :: Or { ref pats } = & first_match_pair. pattern . kind else { unreachable ! ( ) } ;
1436
1432
1437
1433
let remainder_start = self . cfg . start_new_block ( ) ;
1438
- for match_pair in match_pairs {
1439
- let PatKind :: Or { ref pats } = & match_pair. pattern . kind else {
1440
- bug ! ( "Or-patterns should have been sorted to the end" ) ;
1441
- } ;
1442
- let or_span = match_pair. pattern . span ;
1434
+ let or_span = first_match_pair. pattern . span ;
1435
+ // Test the alternatives of this or-pattern.
1436
+ self . test_or_pattern (
1437
+ first_candidate,
1438
+ start_block,
1439
+ remainder_start,
1440
+ pats,
1441
+ or_span,
1442
+ & first_match_pair. place ,
1443
+ fake_borrows,
1444
+ ) ;
1443
1445
1446
+ if !remaining_match_pairs. is_empty ( ) {
1447
+ // If more match pairs remain, test them after each subcandidate.
1448
+ // We could add them to the or-candidates before the call to `test_or_pattern` but this
1449
+ // would make it impossible to detect simplifiable or-patterns. That would guarantee
1450
+ // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`.
1444
1451
first_candidate. visit_leaves ( |leaf_candidate| {
1445
- self . test_or_pattern (
1446
- leaf_candidate,
1447
- remainder_start,
1448
- pats,
1449
- or_span,
1450
- & match_pair. place ,
1452
+ assert ! ( leaf_candidate. match_pairs. is_empty( ) ) ;
1453
+ leaf_candidate. match_pairs . extend ( remaining_match_pairs. iter ( ) . cloned ( ) ) ;
1454
+ let or_start = leaf_candidate. pre_binding_block . unwrap ( ) ;
1455
+ // In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b,
1456
+ // c | d)` will fail too. If there is no guard, we skip testing of `b` by branching
1457
+ // directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`.
1458
+ let or_otherwise = leaf_candidate. otherwise_block . unwrap_or ( remainder_start) ;
1459
+ self . test_candidates_with_or (
1460
+ span,
1461
+ scrutinee_span,
1462
+ & mut [ leaf_candidate] ,
1463
+ or_start,
1464
+ or_otherwise,
1451
1465
fake_borrows,
1452
1466
) ;
1453
1467
} ) ;
1454
1468
}
1455
1469
1470
+ // Test the remaining candidates.
1456
1471
self . match_candidates (
1457
1472
span,
1458
1473
scrutinee_span,
1459
1474
remainder_start,
1460
1475
otherwise_block,
1461
1476
remaining_candidates,
1462
1477
fake_borrows,
1463
- )
1478
+ ) ;
1464
1479
}
1465
1480
1466
1481
#[ instrument(
1467
- skip( self , otherwise , or_span, place, fake_borrows, candidate, pats) ,
1482
+ skip( self , start_block , otherwise_block , or_span, place, fake_borrows, candidate, pats) ,
1468
1483
level = "debug"
1469
1484
) ]
1470
1485
fn test_or_pattern < ' pat > (
1471
1486
& mut self ,
1472
1487
candidate : & mut Candidate < ' pat , ' tcx > ,
1473
- otherwise : BasicBlock ,
1488
+ start_block : BasicBlock ,
1489
+ otherwise_block : BasicBlock ,
1474
1490
pats : & ' pat [ Box < Pat < ' tcx > > ] ,
1475
1491
or_span : Span ,
1476
1492
place : & PlaceBuilder < ' tcx > ,
@@ -1482,16 +1498,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1482
1498
. map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
1483
1499
. collect ( ) ;
1484
1500
let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
1485
- let otherwise = if let Some ( otherwise_block) = candidate. otherwise_block {
1486
- otherwise_block
1487
- } else {
1488
- otherwise
1489
- } ;
1490
1501
self . match_candidates (
1491
1502
or_span,
1492
1503
or_span,
1493
- candidate . pre_binding_block . unwrap ( ) ,
1494
- otherwise ,
1504
+ start_block ,
1505
+ otherwise_block ,
1495
1506
& mut or_candidate_refs,
1496
1507
fake_borrows,
1497
1508
) ;
0 commit comments