@@ -1498,52 +1498,51 @@ struct CopiedLoadBorrowEliminationVisitor final
1498
1498
} // namespace
1499
1499
1500
1500
// ===----------------------------------------------------------------------===//
1501
- // MARK: DestructureThroughDeinit Checking
1501
+ // MARK: Partial Consume/Reinit Checking
1502
1502
// ===----------------------------------------------------------------------===//
1503
1503
1504
+ namespace {
1505
+
1504
1506
// / When partial consumption is enabled, we only allow for destructure through
1505
1507
// / deinits. When partial consumption is disabled, we error on /all/ partial
1506
1508
// / consumption.
1507
- static void checkForDestructure (MarkMustCheckInst *rootAddress, Operand *use,
1508
- TypeTreeLeafTypeRange usedBits,
1509
- DiagnosticEmitter &diagnosticEmitter) {
1510
- LLVM_DEBUG (llvm::dbgs () << " DestructureNeedingUse: " << *use->getUser ());
1509
+ enum class IsPartialConsumeOrReinit_t {
1510
+ IsPartialConsume,
1511
+ IsPartialReinit,
1512
+ };
1513
+
1514
+ } // namespace
1511
1515
1512
- SILFunction *fn = rootAddress->getFunction ();
1516
+ static std::pair<SILType, NominalTypeDecl *>
1517
+ shouldEmitPartialError (UseState &useState, SILInstruction *user,
1518
+ SILType useType, TypeTreeLeafTypeRange usedBits) {
1519
+ SILFunction *fn = useState.getFunction ();
1520
+
1521
+ // We walk down from our ancestor to our projection, emitting an error if
1522
+ // any of our types have a deinit.
1523
+ auto iterType = useState.address ->getType ();
1524
+ if (iterType.isMoveOnlyWrapped ())
1525
+ return {SILType (), nullptr };
1513
1526
1514
- // We walk down from our ancestor to our projection, emitting an error if any
1515
- // of our types have a deinit.
1516
1527
TypeOffsetSizePair pair (usedBits);
1517
- auto targetType = use->get ()->getType ();
1518
- auto iterType = rootAddress->getType ();
1528
+ auto targetType = useType;
1519
1529
TypeOffsetSizePair iterPair (iterType, fn);
1520
1530
1521
- // If our rootAddress is moveonlywrapped, then we know that it must be
1522
- // copyable under the hood meanign that we copy its fields rather than
1523
- // destructure the fields.
1524
- if (iterType.isMoveOnlyWrapped ())
1525
- return ;
1531
+ LLVM_DEBUG (llvm::dbgs () << " Iter Type: " << iterType << ' \n '
1532
+ << " Target Type: " << targetType << ' \n ' );
1526
1533
1527
- // If we are not allowing for any partial consumption, just emit an error
1528
- // immediately.
1529
- if (!rootAddress->getModule ().getASTContext ().LangOpts .hasFeature (
1534
+ if (!fn->getModule ().getASTContext ().LangOpts .hasFeature (
1530
1535
Feature::MoveOnlyPartialConsumption)) {
1536
+ LLVM_DEBUG (llvm::dbgs () << " MoveOnlyPartialConsumption disabled!\n " );
1531
1537
// If the types equal, just bail early.
1532
- if (iterType == targetType)
1533
- return ;
1534
-
1535
- // Otherwise, build up the path string and emit the error.
1536
- SmallString<128 > pathString;
1537
- auto rootType = rootAddress->getType ();
1538
- if (iterType != rootType) {
1539
- llvm::raw_svector_ostream os (pathString);
1540
- pair.constructPathString (iterType, {rootType, fn}, rootType, fn, os);
1538
+ if (iterType == targetType) {
1539
+ LLVM_DEBUG (llvm::dbgs () << " IterType is TargetType! Exiting early "
1540
+ " without emitting error!\n " );
1541
+ return {SILType (), nullptr };
1541
1542
}
1542
1543
1543
- diagnosticEmitter.emitCannotDestructureNominalError (
1544
- rootAddress, pathString, nullptr /* nominal*/ , use->getUser (),
1545
- false /* is for deinit error*/ );
1546
- return ;
1544
+ // Emit the error.
1545
+ return {iterType, nullptr };
1547
1546
}
1548
1547
1549
1548
// Otherwise, walk the type looking for the deinit.
@@ -1558,17 +1557,7 @@ static void checkForDestructure(MarkMustCheckInst *rootAddress, Operand *use,
1558
1557
// through the deinit. Emit a nice error saying what it is. Since we
1559
1558
// are emitting an error, we do a bit more work and construct the
1560
1559
// actual projection string.
1561
- SmallString<128 > pathString;
1562
- auto rootType = rootAddress->getType ();
1563
- if (iterType != rootType) {
1564
- llvm::raw_svector_ostream os (pathString);
1565
- pair.constructPathString (iterType, {rootType, fn}, rootType, fn, os);
1566
- }
1567
-
1568
- diagnosticEmitter.emitCannotDestructureNominalError (
1569
- rootAddress, pathString, nom, use->getUser (),
1570
- true /* is for deinit error*/ );
1571
- break ;
1560
+ return {iterType, nom};
1572
1561
}
1573
1562
}
1574
1563
@@ -1577,6 +1566,63 @@ static void checkForDestructure(MarkMustCheckInst *rootAddress, Operand *use,
1577
1566
std::tie (iterPair, iterType) =
1578
1567
*pair.walkOneLevelTowardsChild (iterPair, iterType, fn);
1579
1568
}
1569
+
1570
+ return {SILType (), nullptr };
1571
+ }
1572
+
1573
+ static void
1574
+ checkForPartialConsume (UseState &useState, DiagnosticEmitter &diagnosticEmitter,
1575
+ SILInstruction *user, SILType useType,
1576
+ TypeTreeLeafTypeRange usedBits,
1577
+ IsPartialConsumeOrReinit_t isPartialConsumeOrReinit) {
1578
+ SILFunction *fn = useState.getFunction ();
1579
+
1580
+ // We walk down from our ancestor to our projection, emitting an error if
1581
+ // any of our types have a deinit.
1582
+ TypeOffsetSizePair pair (usedBits);
1583
+ SILType errorIterType;
1584
+ NominalTypeDecl *nom;
1585
+ std::tie (errorIterType, nom) =
1586
+ shouldEmitPartialError (useState, user, useType, usedBits);
1587
+ if (!errorIterType)
1588
+ return ;
1589
+
1590
+ if (!fn->getModule ().getASTContext ().LangOpts .hasFeature (
1591
+ Feature::MoveOnlyPartialConsumption)) {
1592
+ // Otherwise, build up the path string and emit the error.
1593
+ SmallString<128 > pathString;
1594
+ auto rootType = useState.address ->getType ();
1595
+ if (errorIterType != rootType) {
1596
+ llvm::raw_svector_ostream os (pathString);
1597
+ pair.constructPathString (errorIterType, {rootType, fn}, rootType, fn, os);
1598
+ }
1599
+
1600
+ diagnosticEmitter.emitCannotPartiallyConsumeError (
1601
+ useState.address , pathString, nullptr /* nominal*/ , user,
1602
+ false /* deinit only*/ );
1603
+ return ;
1604
+ }
1605
+
1606
+ LLVM_DEBUG (llvm::dbgs () << " MoveOnlyPartialConsumption enabled!\n " );
1607
+
1608
+ SmallString<128 > pathString;
1609
+ auto rootType = useState.address ->getType ();
1610
+ if (errorIterType != rootType) {
1611
+ llvm::raw_svector_ostream os (pathString);
1612
+ pair.constructPathString (errorIterType, {rootType, fn}, rootType, fn, os);
1613
+ }
1614
+
1615
+ diagnosticEmitter.emitCannotPartiallyConsumeError (
1616
+ useState.address , pathString, nom, user, true /* deinit only*/ );
1617
+ }
1618
+
1619
+ static void
1620
+ checkForPartialConsume (UseState &useState, DiagnosticEmitter &diagnosticEmitter,
1621
+ Operand *op, TypeTreeLeafTypeRange usedBits,
1622
+ IsPartialConsumeOrReinit_t isPartialConsumeOrReinit) {
1623
+ return checkForPartialConsume (useState, diagnosticEmitter, op->getUser (),
1624
+ op->get ()->getType (), usedBits,
1625
+ isPartialConsumeOrReinit);
1580
1626
}
1581
1627
1582
1628
// ===----------------------------------------------------------------------===//
@@ -1778,7 +1824,8 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1778
1824
// If we have a copy_addr, we are either going to have a take or a
1779
1825
// copy... in either case, this copy_addr /is/ going to be a consuming
1780
1826
// operation. Make sure to check if we semantically destructure.
1781
- checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
1827
+ checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
1828
+ IsPartialConsumeOrReinit_t::IsPartialConsume);
1782
1829
1783
1830
if (copyAddr->isTakeOfSrc ()) {
1784
1831
LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
@@ -1965,7 +2012,8 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
1965
2012
} else {
1966
2013
// Now that we know that we are going to perform a take, perform a
1967
2014
// checkForDestructure.
1968
- checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
2015
+ checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
2016
+ IsPartialConsumeOrReinit_t::IsPartialConsume);
1969
2017
1970
2018
// If we emitted an error diagnostic, do not transform further and instead
1971
2019
// mark that we emitted an early diagnostic and return true.
@@ -2020,7 +2068,8 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
2020
2068
// error.
2021
2069
unsigned numDiagnostics =
2022
2070
moveChecker.diagnosticEmitter .getDiagnosticCount ();
2023
- checkForDestructure (markedValue, op, *leafRange, diagnosticEmitter);
2071
+ checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
2072
+ IsPartialConsumeOrReinit_t::IsPartialConsume);
2024
2073
if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
2025
2074
LLVM_DEBUG (llvm::dbgs ()
2026
2075
<< " Emitting destructure through deinit error!\n " );
0 commit comments