Factor out the special handling of or-patterns · rust-lang/rust@bff4d21 (original) (raw)

`@@ -1427,108 +1427,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

`

1427

1427

`` /// Note how we test x twice. This is the tradeoff of backtracking automata: we prefer smaller

``

1428

1428

`/// code size at the expense of non-optimal code paths.

`

1429

1429

`#[instrument(skip(self), level = "debug")]

`

1430

``

`-

fn match_candidates<'pat>(

`

``

1430

`+

fn match_candidates(

`

1431

1431

`&mut self,

`

1432

1432

`span: Span,

`

1433

1433

`scrutinee_span: Span,

`

1434

1434

`start_block: BasicBlock,

`

1435

1435

`otherwise_block: BasicBlock,

`

1436

``

`-

candidates: &mut [&mut Candidate<'pat, 'tcx>],

`

``

1436

`+

candidates: &mut [&mut Candidate<'_, 'tcx>],

`

1437

1437

`) {

`

1438

``

`-

// We process or-patterns here. If any candidate starts with an or-pattern, we have to

`

1439

``

`-

// expand the or-pattern before we can proceed further.

`

1440

``

`-

//

`

1441

``

`-

// We can't expand them freely however. The rule is: if the candidate has an or-pattern as

`

1442

``

`-

// its only remaining match pair, we can expand it freely. If it has other match pairs, we

`

1443

``

`-

// can expand it but we can't process more candidates after it.

`

1444

``

`-

//

`

1445

``

`` -

// If we didn't stop, the otherwise cases could get mixed up. E.g. in the following,

``

1446

``

`` -

// or-pattern simplification (in merge_trivial_subcandidates) makes it so the 1 and 2

``

1447

``

`` -

// cases branch to a same block (which then tests false). If we took (2, _) in the same

``

1448

``

`` -

// set of candidates, when we reach the block that tests false we don't know whether we

``

1449

``

`` -

// came from 1 or 2, hence we can't know where to branch on failure.

``

1450

``


// ```ignore(illustrative)

1451

``

`-

// match (1, true) {

`

1452

``

`-

// (1 | 2, false) => {},

`

1453

``

`-

// (2, _) => {},

`

1454

``

`-

// _ => {}

`

1455

``

`-

// }

`

1456

``


// ```

1457

``

`-

//

`

1458

``

`` -

// We therefore split the candidates slice in two, expand or-patterns in the first half,

``

1459

``

`-

// and process both halves separately.

`

1460

``

`-

let mut expand_until = 0;

`

1461

``

`-

for (i, candidate) in candidates.iter().enumerate() {

`

1462

``

`-

if matches!(

`

``

1438

`+

// If any candidate starts with an or-pattern, we have to expand the or-pattern before we

`

``

1439

`+

// can proceed further.

`

``

1440

`+

let expand_ors = candidates.iter().any(|candidate| {

`

``

1441

`+

matches!(

`

1463

1442

`&*candidate.match_pairs,

`

1464

1443

`[MatchPair { test_case: TestCase::Or { .. }, .. }, ..]

`

1465

``

`-

) {

`

1466

``

`-

expand_until = i + 1;

`

1467

``

`-

if candidate.match_pairs.len() > 1 {

`

1468

``

`-

break;

`

1469

``

`-

}

`

1470

``

`-

}

`

1471

``

`-

if expand_until != 0 {

`

1472

``

`-

expand_until = i + 1;

`

1473

``

`-

}

`

1474

``

`-

}

`

1475

``

`-

let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);

`

1476

``

-

``

1444

`+

)

`

``

1445

`+

});

`

1477

1446

`ensure_sufficient_stack(|| {

`

1478

``

`-

if candidates_to_expand.is_empty() {

`

``

1447

`+

if !expand_ors {

`

1479

1448

`// No candidates start with an or-pattern, we can continue.

`

1480

1449

`self.match_expanded_candidates(

`

1481

1450

` span,

`

1482

1451

` scrutinee_span,

`

1483

1452

` start_block,

`

1484

1453

` otherwise_block,

`

1485

``

`-

remaining_candidates,

`

``

1454

`+

candidates,

`

1486

1455

`);

`

1487

1456

`} else {

`

1488

``

`` -

// Expand one level of or-patterns for each candidate in candidates_to_expand.

``

1489

``

`-

let mut expanded_candidates = Vec::new();

`

1490

``

`-

for candidate in candidates_to_expand.iter_mut() {

`

1491

``

`-

if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] =

`

1492

``

`-

&*candidate.match_pairs

`

1493

``

`-

{

`

1494

``

`-

let or_match_pair = candidate.match_pairs.remove(0);

`

1495

``

`-

// Expand the or-pattern into subcandidates.

`

1496

``

`-

self.create_or_subcandidates(candidate, or_match_pair);

`

1497

``

`-

// Collect the newly created subcandidates.

`

1498

``

`-

for subcandidate in candidate.subcandidates.iter_mut() {

`

1499

``

`-

expanded_candidates.push(subcandidate);

`

1500

``

`-

}

`

1501

``

`-

} else {

`

1502

``

`-

expanded_candidates.push(candidate);

`

1503

``

`-

}

`

1504

``

`-

}

`

1505

``

-

1506

``

`-

// Process the expanded candidates.

`

1507

``

`-

let remainder_start = self.cfg.start_new_block();

`

1508

``

`-

// There might be new or-patterns obtained from expanding the old ones, so we call

`

1509

``

`` -

// match_candidates again.

``

1510

``

`-

self.match_candidates(

`

``

1457

`+

self.expand_and_match_or_candidates(

`

1511

1458

` span,

`

1512

1459

` scrutinee_span,

`

1513

1460

` start_block,

`

1514

``

`-

remainder_start,

`

1515

``

`-

expanded_candidates.as_mut_slice(),

`

1516

``

`-

);

`

1517

``

-

1518

``

`-

// Simplify subcandidates and process any leftover match pairs.

`

1519

``

`-

for candidate in candidates_to_expand {

`

1520

``

`-

if !candidate.subcandidates.is_empty() {

`

1521

``

`-

self.finalize_or_candidate(span, scrutinee_span, candidate);

`

1522

``

`-

}

`

1523

``

`-

}

`

1524

``

-

1525

``

`-

// Process the remaining candidates.

`

1526

``

`-

self.match_candidates(

`

1527

``

`-

span,

`

1528

``

`-

scrutinee_span,

`

1529

``

`-

remainder_start,

`

1530

1461

` otherwise_block,

`

1531

``

`-

remaining_candidates,

`

``

1462

`+

candidates,

`

1532

1463

`);

`

1533

1464

`}

`

1534

1465

`});

`

`@@ -1624,6 +1555,98 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

`

1624

1555

` otherwise_block

`

1625

1556

`}

`

1626

1557

``

``

1558

`+

/// Takes a list of candidates such that some of the candidates' first match pairs are

`

``

1559

`+

/// or-patterns, expands as many or-patterns as possible, and processes the resulting

`

``

1560

`+

/// candidates.

`

``

1561

`+

fn expand_and_match_or_candidates(

`

``

1562

`+

&mut self,

`

``

1563

`+

span: Span,

`

``

1564

`+

scrutinee_span: Span,

`

``

1565

`+

start_block: BasicBlock,

`

``

1566

`+

otherwise_block: BasicBlock,

`

``

1567

`+

candidates: &mut [&mut Candidate<'_, 'tcx>],

`

``

1568

`+

) {

`

``

1569

`+

// We can't expand or-patterns freely. The rule is: if the candidate has an

`

``

1570

`+

// or-pattern as its only remaining match pair, we can expand it freely. If it has

`

``

1571

`+

// other match pairs, we can expand it but we can't process more candidates after

`

``

1572

`+

// it.

`

``

1573

`+

//

`

``

1574

`` +

// If we didn't stop, the otherwise cases could get mixed up. E.g. in the

``

``

1575

`` +

// following, or-pattern simplification (in merge_trivial_subcandidates) makes it

``

``

1576

`` +

// so the 1 and 2 cases branch to a same block (which then tests false). If we

``

``

1577

`` +

// took (2, _) in the same set of candidates, when we reach the block that tests

``

``

1578

`` +

// false we don't know whether we came from 1 or 2, hence we can't know where

``

``

1579

`+

// to branch on failure.

`

``

1580

`+

//

`

``

1581


// ```ignore(illustrative)

``

1582

`+

// match (1, true) {

`

``

1583

`+

// (1 | 2, false) => {},

`

``

1584

`+

// (2, _) => {},

`

``

1585

`+

// _ => {}

`

``

1586

`+

// }

`

``

1587


// ```

``

1588

`+

//

`

``

1589

`` +

// We therefore split the candidates slice in two, expand or-patterns in the first half,

``

``

1590

`+

// and process the rest separately.

`

``

1591

`+

let mut expand_until = 0;

`

``

1592

`+

for (i, candidate) in candidates.iter().enumerate() {

`

``

1593

`+

expand_until = i + 1;

`

``

1594

`+

if candidate.match_pairs.len() > 1

`

``

1595

`+

&& matches!(&candidate.match_pairs[0].test_case, TestCase::Or { .. })

`

``

1596

`+

{

`

``

1597

`+

// The candidate has an or-pattern as well as more match pairs: we must

`

``

1598

`+

// split the candidates list here.

`

``

1599

`+

break;

`

``

1600

`+

}

`

``

1601

`+

}

`

``

1602

`+

let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);

`

``

1603

+

``

1604

`` +

// Expand one level of or-patterns for each candidate in candidates_to_expand.

``

``

1605

`+

let mut expanded_candidates = Vec::new();

`

``

1606

`+

for candidate in candidates_to_expand.iter_mut() {

`

``

1607

`+

if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = &*candidate.match_pairs

`

``

1608

`+

{

`

``

1609

`+

let or_match_pair = candidate.match_pairs.remove(0);

`

``

1610

`+

// Expand the or-pattern into subcandidates.

`

``

1611

`+

self.create_or_subcandidates(candidate, or_match_pair);

`

``

1612

`+

// Collect the newly created subcandidates.

`

``

1613

`+

for subcandidate in candidate.subcandidates.iter_mut() {

`

``

1614

`+

expanded_candidates.push(subcandidate);

`

``

1615

`+

}

`

``

1616

`+

} else {

`

``

1617

`+

expanded_candidates.push(candidate);

`

``

1618

`+

}

`

``

1619

`+

}

`

``

1620

+

``

1621

`+

// Process the expanded candidates.

`

``

1622

`+

let remainder_start = self.cfg.start_new_block();

`

``

1623

`+

// There might be new or-patterns obtained from expanding the old ones, so we call

`

``

1624

`` +

// match_candidates again.

``

``

1625

`+

self.match_candidates(

`

``

1626

`+

span,

`

``

1627

`+

scrutinee_span,

`

``

1628

`+

start_block,

`

``

1629

`+

remainder_start,

`

``

1630

`+

expanded_candidates.as_mut_slice(),

`

``

1631

`+

);

`

``

1632

+

``

1633

`+

// Simplify subcandidates and process any leftover match pairs.

`

``

1634

`+

for candidate in candidates_to_expand {

`

``

1635

`+

if !candidate.subcandidates.is_empty() {

`

``

1636

`+

self.finalize_or_candidate(span, scrutinee_span, candidate);

`

``

1637

`+

}

`

``

1638

`+

}

`

``

1639

+

``

1640

`+

// Process the remaining candidates.

`

``

1641

`+

self.match_candidates(

`

``

1642

`+

span,

`

``

1643

`+

scrutinee_span,

`

``

1644

`+

remainder_start,

`

``

1645

`+

otherwise_block,

`

``

1646

`+

remaining_candidates,

`

``

1647

`+

);

`

``

1648

`+

}

`

``

1649

+

1627

1650

`/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new

`

1628

1651

`/// subcandidate. Any candidate that has been expanded that way should be passed to

`

1629

1652

`` /// finalize_or_candidate after its subcandidates have been processed.

``