@@ -1615,28 +1615,18 @@ struct CopiedLoadBorrowEliminationVisitor
1615
1615
// MARK: Partial Consume/Reinit Checking
1616
1616
// ===----------------------------------------------------------------------===//
1617
1617
1618
- namespace {
1619
-
1620
- // / When partial consumption is enabled, we only allow for destructure through
1621
- // / deinits. When partial consumption is disabled, we error on /all/ partial
1622
- // / consumption.
1623
- enum class IsPartialConsumeOrReinit_t {
1624
- IsPartialConsume,
1625
- IsPartialReinit,
1626
- };
1627
-
1628
- } // namespace
1629
-
1630
- static std::pair<SILType, NominalTypeDecl *>
1631
- shouldEmitPartialError (UseState &useState, SILInstruction *user,
1632
- SILType useType, TypeTreeLeafTypeRange usedBits) {
1618
+ // / Whether an error should be emitted in response to a partial consumption.
1619
+ static llvm::Optional<PartialMutationError>
1620
+ shouldEmitPartialMutationError (UseState &useState, SILInstruction *user,
1621
+ SILType useType,
1622
+ TypeTreeLeafTypeRange usedBits) {
1633
1623
SILFunction *fn = useState.getFunction ();
1634
1624
1635
1625
// We walk down from our ancestor to our projection, emitting an error if
1636
1626
// any of our types have a deinit.
1637
1627
auto iterType = useState.address ->getType ();
1638
1628
if (iterType.isMoveOnlyWrapped ())
1639
- return {SILType (), nullptr };
1629
+ return {};
1640
1630
1641
1631
TypeOffsetSizePair pair (usedBits);
1642
1632
auto targetType = useType;
@@ -1652,13 +1642,15 @@ shouldEmitPartialError(UseState &useState, SILInstruction *user,
1652
1642
if (iterType == targetType) {
1653
1643
LLVM_DEBUG (llvm::dbgs () << " IterType is TargetType! Exiting early "
1654
1644
" without emitting error!\n " );
1655
- return {SILType (), nullptr };
1645
+ return {};
1656
1646
}
1657
1647
1658
1648
// Emit the error.
1659
- return {iterType, nullptr };
1649
+ return {PartialMutationError::featureDisabled ( iterType) };
1660
1650
}
1661
1651
1652
+ LLVM_DEBUG (llvm::dbgs () << " MoveOnlyPartialConsumption enabled!\n " );
1653
+
1662
1654
// Otherwise, walk the type looking for the deinit.
1663
1655
while (iterType != targetType) {
1664
1656
// If we have a nominal type as our parent type, see if it has a
@@ -1671,7 +1663,7 @@ shouldEmitPartialError(UseState &useState, SILInstruction *user,
1671
1663
// through the deinit. Emit a nice error saying what it is. Since we
1672
1664
// are emitting an error, we do a bit more work and construct the
1673
1665
// actual projection string.
1674
- return {iterType, nom};
1666
+ return {PartialMutationError::hasDeinit ( iterType, * nom) };
1675
1667
}
1676
1668
}
1677
1669
@@ -1681,103 +1673,24 @@ shouldEmitPartialError(UseState &useState, SILInstruction *user,
1681
1673
*pair.walkOneLevelTowardsChild (iterPair, iterType, fn);
1682
1674
}
1683
1675
1684
- return {SILType (), nullptr };
1685
- }
1686
-
1687
- static void
1688
- checkForPartialConsume (UseState &useState, DiagnosticEmitter &diagnosticEmitter,
1689
- SILInstruction *user, SILType useType,
1690
- TypeTreeLeafTypeRange usedBits,
1691
- IsPartialConsumeOrReinit_t isPartialConsumeOrReinit) {
1692
- SILFunction *fn = useState.getFunction ();
1693
-
1694
- // We walk down from our ancestor to our projection, emitting an error if
1695
- // any of our types have a deinit.
1696
- TypeOffsetSizePair pair (usedBits);
1697
- SILType errorIterType;
1698
- NominalTypeDecl *nom;
1699
- std::tie (errorIterType, nom) =
1700
- shouldEmitPartialError (useState, user, useType, usedBits);
1701
- if (!errorIterType)
1702
- return ;
1703
-
1704
- if (!fn->getModule ().getASTContext ().LangOpts .hasFeature (
1705
- Feature::MoveOnlyPartialConsumption)) {
1706
- // Otherwise, build up the path string and emit the error.
1707
- SmallString<128 > pathString;
1708
- auto rootType = useState.address ->getType ();
1709
- if (errorIterType != rootType) {
1710
- llvm::raw_svector_ostream os (pathString);
1711
- pair.constructPathString (errorIterType, {rootType, fn}, rootType, fn, os);
1712
- }
1713
-
1714
- diagnosticEmitter.emitCannotPartiallyConsumeError (
1715
- useState.address , pathString, nullptr /* nominal*/ , user,
1716
- false /* deinit only*/ );
1717
- return ;
1718
- }
1719
-
1720
- LLVM_DEBUG (llvm::dbgs () << " MoveOnlyPartialConsumption enabled!\n " );
1721
-
1722
- SmallString<128 > pathString;
1723
- auto rootType = useState.address ->getType ();
1724
- if (errorIterType != rootType) {
1725
- llvm::raw_svector_ostream os (pathString);
1726
- pair.constructPathString (errorIterType, {rootType, fn}, rootType, fn, os);
1727
- }
1728
-
1729
- diagnosticEmitter.emitCannotPartiallyConsumeError (
1730
- useState.address , pathString, nom, user, true /* deinit only*/ );
1731
- }
1732
-
1733
- static void
1734
- checkForPartialConsume (UseState &useState, DiagnosticEmitter &diagnosticEmitter,
1735
- Operand *op, TypeTreeLeafTypeRange usedBits,
1736
- IsPartialConsumeOrReinit_t isPartialConsumeOrReinit) {
1737
- return checkForPartialConsume (useState, diagnosticEmitter, op->getUser (),
1738
- op->get ()->getType (), usedBits,
1739
- isPartialConsumeOrReinit);
1676
+ return {};
1740
1677
}
1741
1678
1742
- static void diagnosePartialReinitError (UseState &useState,
1743
- DiagnosticEmitter &diagnosticEmitter,
1744
- SILInstruction *user, SILType errorType,
1745
- NominalTypeDecl *nom,
1746
- SILInstruction *earlierConsumingUse,
1747
- TypeTreeLeafTypeRange usedBits) {
1748
- SILFunction *fn = useState.getFunction ();
1749
-
1679
+ static bool checkForPartialMutation (UseState &useState,
1680
+ DiagnosticEmitter &diagnosticEmitter,
1681
+ SILInstruction *user, SILType useType,
1682
+ TypeTreeLeafTypeRange usedBits,
1683
+ PartialMutation partialMutateKind) {
1750
1684
// We walk down from our ancestor to our projection, emitting an error if
1751
1685
// any of our types have a deinit.
1752
- TypeOffsetSizePair pair (usedBits);
1753
- if (!fn->getModule ().getASTContext ().LangOpts .hasFeature (
1754
- Feature::MoveOnlyPartialConsumption)) {
1755
- // Otherwise, build up the path string and emit the error.
1756
- SmallString<128 > pathString;
1757
- auto rootType = useState.address ->getType ();
1758
- if (errorType != rootType) {
1759
- llvm::raw_svector_ostream os (pathString);
1760
- pair.constructPathString (errorType, {rootType, fn}, rootType, fn, os);
1761
- }
1762
-
1763
- diagnosticEmitter.emitCannotPartiallyReinitError (
1764
- useState.address , pathString, nullptr /* nominal*/ , user,
1765
- earlierConsumingUse, false /* deinit only*/ );
1766
- return ;
1767
- }
1768
-
1769
- LLVM_DEBUG (llvm::dbgs () << " MoveOnlyPartialConsumption enabled!\n " );
1770
-
1771
- SmallString<128 > pathString;
1772
- auto rootType = useState.address ->getType ();
1773
- if (errorType != rootType) {
1774
- llvm::raw_svector_ostream os (pathString);
1775
- pair.constructPathString (errorType, {rootType, fn}, rootType, fn, os);
1776
- }
1686
+ auto error =
1687
+ shouldEmitPartialMutationError (useState, user, useType, usedBits);
1688
+ if (!error)
1689
+ return false ;
1777
1690
1778
- diagnosticEmitter.emitCannotPartiallyReinitError (
1779
- useState.address , pathString, nom, user, earlierConsumingUse,
1780
- true /* deinit only */ ) ;
1691
+ diagnosticEmitter.emitCannotPartiallyMutateError (
1692
+ useState.address , error. value (), user, usedBits, partialMutateKind);
1693
+ return true ;
1781
1694
}
1782
1695
1783
1696
namespace {
@@ -1791,14 +1704,6 @@ struct PartialReinitChecker {
1791
1704
1792
1705
void
1793
1706
performPartialReinitChecking (FieldSensitiveMultiDefPrunedLiveRange &liveness);
1794
-
1795
- private:
1796
- void checkForPartialConsumeOrInitError (
1797
- SILInstruction *user, SILType useType, TypeTreeLeafTypeRange usedBits,
1798
- IsPartialConsumeOrReinit_t isPartialConsumeOrReinit) {
1799
- ::checkForPartialConsume (useState, diagnosticEmitter, user, useType,
1800
- usedBits, isPartialConsumeOrReinit);
1801
- }
1802
1707
};
1803
1708
1804
1709
} // namespace
@@ -1819,18 +1724,10 @@ void PartialReinitChecker::performPartialReinitChecking(
1819
1724
emittedError = !liveness.findEarlierConsumingUse (
1820
1725
initToValues.first , index,
1821
1726
[&](SILInstruction *consumingInst) -> bool {
1822
- SILType errorType;
1823
- NominalTypeDecl *nom;
1824
- std::tie (errorType, nom) = shouldEmitPartialError (
1825
- useState, initToValues.first , value->getType (),
1826
- TypeTreeLeafTypeRange (index, index + 1 ));
1827
- if (!errorType)
1828
- return true ;
1829
-
1830
- diagnosePartialReinitError (
1831
- useState, diagnosticEmitter, initToValues.first , errorType,
1832
- nom, consumingInst, TypeTreeLeafTypeRange (index, index + 1 ));
1833
- return false ;
1727
+ return !checkForPartialMutation (
1728
+ useState, diagnosticEmitter, initToValues.first ,
1729
+ value->getType (), TypeTreeLeafTypeRange (index, index + 1 ),
1730
+ PartialMutation::reinit (*consumingInst));
1834
1731
});
1835
1732
1836
1733
// If we emitted an error for this index break. We only want to emit one
@@ -1862,18 +1759,10 @@ void PartialReinitChecker::performPartialReinitChecking(
1862
1759
emittedError = !liveness.findEarlierConsumingUse (
1863
1760
reinitToValues.first , index,
1864
1761
[&](SILInstruction *consumingInst) -> bool {
1865
- SILType errorType;
1866
- NominalTypeDecl *nom;
1867
- std::tie (errorType, nom) = shouldEmitPartialError (
1868
- useState, reinitToValues.first , value->getType (),
1869
- TypeTreeLeafTypeRange (index, index + 1 ));
1870
- if (!errorType)
1871
- return true ;
1872
-
1873
- diagnosePartialReinitError (
1874
- useState, diagnosticEmitter, reinitToValues.first , errorType,
1875
- nom, consumingInst, TypeTreeLeafTypeRange (index, index + 1 ));
1876
- return false ;
1762
+ return !checkForPartialMutation (
1763
+ useState, diagnosticEmitter, reinitToValues.first ,
1764
+ value->getType (), TypeTreeLeafTypeRange (index, index + 1 ),
1765
+ PartialMutation::reinit (*consumingInst));
1877
1766
});
1878
1767
if (emittedError)
1879
1768
break ;
@@ -2102,8 +1991,9 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
2102
1991
// If we have a copy_addr, we are either going to have a take or a
2103
1992
// copy... in either case, this copy_addr /is/ going to be a consuming
2104
1993
// operation. Make sure to check if we semantically destructure.
2105
- checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
2106
- IsPartialConsumeOrReinit_t::IsPartialConsume);
1994
+ checkForPartialMutation (useState, diagnosticEmitter, op->getUser (),
1995
+ op->get ()->getType (), *leafRange,
1996
+ PartialMutation::consume ());
2107
1997
2108
1998
if (copyAddr->isTakeOfSrc ()) {
2109
1999
LLVM_DEBUG (llvm::dbgs () << " Found take: " << *user);
@@ -2296,8 +2186,9 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
2296
2186
} else {
2297
2187
// Now that we know that we are going to perform a take, perform a
2298
2188
// checkForDestructure.
2299
- checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
2300
- IsPartialConsumeOrReinit_t::IsPartialConsume);
2189
+ checkForPartialMutation (useState, diagnosticEmitter, op->getUser (),
2190
+ op->get ()->getType (), *leafRange,
2191
+ PartialMutation::consume ());
2301
2192
2302
2193
// If we emitted an error diagnostic, do not transform further and instead
2303
2194
// mark that we emitted an early diagnostic and return true.
@@ -2352,8 +2243,9 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
2352
2243
// error.
2353
2244
unsigned numDiagnostics =
2354
2245
moveChecker.diagnosticEmitter .getDiagnosticCount ();
2355
- checkForPartialConsume (useState, diagnosticEmitter, op, *leafRange,
2356
- IsPartialConsumeOrReinit_t::IsPartialConsume);
2246
+ checkForPartialMutation (useState, diagnosticEmitter, op->getUser (),
2247
+ op->get ()->getType (), *leafRange,
2248
+ PartialMutation::consume ());
2357
2249
if (numDiagnostics != moveChecker.diagnosticEmitter .getDiagnosticCount ()) {
2358
2250
LLVM_DEBUG (llvm::dbgs ()
2359
2251
<< " Emitting destructure through deinit error!\n " );
0 commit comments