@@ -58,6 +58,29 @@ using Region = PartitionPrimitives::Region;
58
58
// MARK: Utilities
59
59
// ===----------------------------------------------------------------------===//
60
60
61
+ static SILValue stripFunctionConversions (SILValue val) {
62
+ while (true ) {
63
+ if (auto ti = dyn_cast<ThinToThickFunctionInst>(val)) {
64
+ val = ti->getOperand ();
65
+ continue ;
66
+ }
67
+
68
+ if (auto cfi = dyn_cast<ConvertFunctionInst>(val)) {
69
+ val = cfi->getOperand ();
70
+ continue ;
71
+ }
72
+
73
+ if (auto cvt = dyn_cast<ConvertEscapeToNoEscapeInst>(val)) {
74
+ val = cvt->getOperand ();
75
+ continue ;
76
+ }
77
+
78
+ break ;
79
+ }
80
+
81
+ return val;
82
+ }
83
+
61
84
static std::optional<DiagnosticBehavior>
62
85
getDiagnosticBehaviorLimitForValue (SILValue value) {
63
86
auto *nom = value->getType ().getNominalOrBoundGenericNominal ();
@@ -72,6 +95,38 @@ getDiagnosticBehaviorLimitForValue(SILValue value) {
72
95
return getConcurrencyDiagnosticBehaviorLimit (nom, fromDC);
73
96
}
74
97
98
+ static std::optional<DiagnosticBehavior>
99
+ getDiagnosticBehaviorLimitForCapturedValue (CapturedValue value) {
100
+ ValueDecl *decl = value.getDecl ();
101
+ auto *nom = decl->getInterfaceType ()->getNominalOrBoundGenericNominal ();
102
+ if (!nom)
103
+ return {};
104
+
105
+ auto *fromDC = decl->getInnermostDeclContext ();
106
+ return getConcurrencyDiagnosticBehaviorLimit (nom, fromDC);
107
+ }
108
+
109
+ // / Find the most conservative diagnostic behavior by taking the max over all
110
+ // / DiagnosticBehavior for the captured values.
111
+ static std::optional<DiagnosticBehavior>
112
+ getDiagnosticBehaviorLimitForCapturedValues (
113
+ ArrayRef<CapturedValue> capturedValues) {
114
+ using UnderlyingType = std::underlying_type<DiagnosticBehavior>::type;
115
+
116
+ std::optional<DiagnosticBehavior> diagnosticBehavior;
117
+ for (auto value : capturedValues) {
118
+ auto lhs = UnderlyingType (
119
+ diagnosticBehavior.value_or (DiagnosticBehavior::Unspecified));
120
+ auto rhs = UnderlyingType (
121
+ getDiagnosticBehaviorLimitForCapturedValue (value).value_or (
122
+ DiagnosticBehavior::Unspecified));
123
+ auto result = DiagnosticBehavior (std::max (lhs, rhs));
124
+ if (result != DiagnosticBehavior::Unspecified)
125
+ diagnosticBehavior = result;
126
+ }
127
+ return diagnosticBehavior;
128
+ }
129
+
75
130
static std::optional<SILDeclRef> getDeclRefForCallee (SILInstruction *inst) {
76
131
auto fas = FullApplySite::isa (inst);
77
132
if (!fas)
@@ -1318,6 +1373,98 @@ class TransferNonTransferrableDiagnosticEmitter {
1318
1373
.limitBehaviorIf (getBehaviorLimit ());
1319
1374
}
1320
1375
1376
+ // / Only use if we were able to find the actual isolated value.
1377
+ void emitTypedSendingNeverSendableToSendingClosureParamDirectlyIsolated (
1378
+ SILLocation loc, CapturedValue capturedValue) {
1379
+ SmallString<64 > descriptiveKindStr;
1380
+ {
1381
+ llvm::raw_svector_ostream os (descriptiveKindStr);
1382
+ if (getIsolationRegionInfo ().getIsolationInfo ().isTaskIsolated ()) {
1383
+ os << " code in the current task" ;
1384
+ } else {
1385
+ getIsolationRegionInfo ().printForDiagnostics (os);
1386
+ os << " code" ;
1387
+ }
1388
+ }
1389
+
1390
+ diagnoseError (loc,
1391
+ diag::regionbasedisolation_typed_tns_passed_sending_closure,
1392
+ descriptiveKindStr)
1393
+ .highlight (loc.getSourceRange ())
1394
+ .limitBehaviorIf (
1395
+ getDiagnosticBehaviorLimitForCapturedValue (capturedValue));
1396
+
1397
+ auto capturedLoc = RegularLocation (capturedValue.getLoc ());
1398
+ if (getIsolationRegionInfo ().getIsolationInfo ().isTaskIsolated ()) {
1399
+ auto diag = diag::
1400
+ regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_task_isolated;
1401
+ diagnoseNote (capturedLoc, diag, capturedValue.getDecl ()->getName ());
1402
+ return ;
1403
+ }
1404
+
1405
+ descriptiveKindStr.clear ();
1406
+ {
1407
+ llvm::raw_svector_ostream os (descriptiveKindStr);
1408
+ getIsolationRegionInfo ().printForDiagnostics (os);
1409
+ }
1410
+
1411
+ auto diag = diag::
1412
+ regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value;
1413
+ diagnoseNote (capturedLoc, diag, descriptiveKindStr,
1414
+ capturedValue.getDecl ()->getName ());
1415
+ }
1416
+
1417
+ void emitTypedSendingNeverSendableToSendingClosureParam (
1418
+ SILLocation loc, ArrayRef<CapturedValue> capturedValues) {
1419
+ SmallString<64 > descriptiveKindStr;
1420
+ {
1421
+ llvm::raw_svector_ostream os (descriptiveKindStr);
1422
+ if (getIsolationRegionInfo ().getIsolationInfo ().isTaskIsolated ()) {
1423
+ os << " code in the current task" ;
1424
+ } else {
1425
+ getIsolationRegionInfo ().printForDiagnostics (os);
1426
+ os << " code" ;
1427
+ }
1428
+ }
1429
+
1430
+ auto behaviorLimit =
1431
+ getDiagnosticBehaviorLimitForCapturedValues (capturedValues);
1432
+ diagnoseError (loc,
1433
+ diag::regionbasedisolation_typed_tns_passed_sending_closure,
1434
+ descriptiveKindStr)
1435
+ .highlight (loc.getSourceRange ())
1436
+ .limitBehaviorIf (behaviorLimit);
1437
+
1438
+ if (capturedValues.size () == 1 ) {
1439
+ auto captured = capturedValues.front ();
1440
+ auto capturedLoc = RegularLocation (captured.getLoc ());
1441
+ if (getIsolationRegionInfo ().getIsolationInfo ().isTaskIsolated ()) {
1442
+ auto diag = diag::
1443
+ regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_task_isolated;
1444
+ diagnoseNote (capturedLoc, diag, captured.getDecl ()->getName ());
1445
+ return ;
1446
+ }
1447
+
1448
+ descriptiveKindStr.clear ();
1449
+ {
1450
+ llvm::raw_svector_ostream os (descriptiveKindStr);
1451
+ getIsolationRegionInfo ().printForDiagnostics (os);
1452
+ }
1453
+ auto diag = diag::
1454
+ regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region;
1455
+ diagnoseNote (capturedLoc, diag, descriptiveKindStr,
1456
+ captured.getDecl ()->getName ());
1457
+ return ;
1458
+ }
1459
+
1460
+ for (auto captured : capturedValues) {
1461
+ auto capturedLoc = RegularLocation (captured.getLoc ());
1462
+ auto diag = diag::
1463
+ regionbasedisolation_typed_tns_passed_to_sending_closure_helper_multiple_value;
1464
+ diagnoseNote (capturedLoc, diag, captured.getDecl ()->getName ());
1465
+ }
1466
+ }
1467
+
1321
1468
void emitNamedOnlyError (SILLocation loc, Identifier name) {
1322
1469
diagnoseError (loc, diag::regionbasedisolation_named_transfer_yields_race,
1323
1470
name)
@@ -1455,12 +1602,13 @@ class TransferNonTransferrableDiagnosticEmitter {
1455
1602
class TransferNonTransferrableDiagnosticInferrer {
1456
1603
struct AutoClosureWalker ;
1457
1604
1605
+ RegionAnalysisValueMap &valueMap;
1458
1606
TransferNonTransferrableDiagnosticEmitter diagnosticEmitter;
1459
1607
1460
1608
public:
1461
1609
TransferNonTransferrableDiagnosticInferrer (
1462
- TransferredNonTransferrableInfo info)
1463
- : diagnosticEmitter(info) {}
1610
+ RegionAnalysisValueMap &valueMap, TransferredNonTransferrableInfo info)
1611
+ : valueMap(valueMap), diagnosticEmitter(info) {}
1464
1612
1465
1613
// / Gathers diagnostics. Returns false if we emitted a "I don't understand
1466
1614
// / error". If we emit such an error, we should bail without emitting any
@@ -1474,10 +1622,94 @@ class TransferNonTransferrableDiagnosticInferrer {
1474
1622
bool initForIsolatedPartialApply (
1475
1623
Operand *op, AbstractClosureExpr *ace,
1476
1624
std::optional<ActorIsolation> actualCallerIsolation = {});
1625
+
1626
+ bool initForSendingPartialApply (FullApplySite fas, Operand *pai);
1627
+
1628
+ std::optional<unsigned >
1629
+ getIsolatedValuePartialApplyIndex (PartialApplyInst *pai,
1630
+ SILValue isolatedValue) {
1631
+ for (auto &paiOp : ApplySite (pai).getArgumentOperands ()) {
1632
+ if (valueMap.getTrackableValue (paiOp.get ()).getRepresentative () ==
1633
+ isolatedValue) {
1634
+ // isolated_any causes all partial apply parameters to be shifted by 1
1635
+ // due to the implicit isolated any parameter.
1636
+ unsigned isIsolatedAny = pai->getFunctionType ()->getIsolation () ==
1637
+ SILFunctionTypeIsolation::Erased;
1638
+ return ApplySite (pai).getAppliedArgIndex (paiOp) - isIsolatedAny;
1639
+ }
1640
+ }
1641
+
1642
+ return {};
1643
+ }
1477
1644
};
1478
1645
1479
1646
} // namespace
1480
1647
1648
+ bool TransferNonTransferrableDiagnosticInferrer::initForSendingPartialApply (
1649
+ FullApplySite fas, Operand *paiOp) {
1650
+ auto *pai =
1651
+ dyn_cast<PartialApplyInst>(stripFunctionConversions (paiOp->get ()));
1652
+ if (!pai)
1653
+ return false ;
1654
+
1655
+ // For now we want this to be really narrow and to only apply to closure
1656
+ // literals.
1657
+ auto *ce = pai->getLoc ().getAsASTNode <ClosureExpr>();
1658
+ if (!ce)
1659
+ return false ;
1660
+
1661
+ // Ok, we now know we have a partial apply and it is a closure literal. Lets
1662
+ // see if we can find the exact thing that caused the closure literal to be
1663
+ // actor isolated.
1664
+ auto isolationInfo = diagnosticEmitter.getIsolationRegionInfo ();
1665
+ if (isolationInfo->hasIsolatedValue ()) {
1666
+ // Now that we have the value, see if that value is one of our captured
1667
+ // values.
1668
+ auto isolatedValue = isolationInfo->getIsolatedValue ();
1669
+ auto matchingElt = getIsolatedValuePartialApplyIndex (pai, isolatedValue);
1670
+ if (matchingElt) {
1671
+ // Ok, we found the matching element. Lets emit our diagnostic!
1672
+ auto capture = ce->getCaptureInfo ().getCaptures ()[*matchingElt];
1673
+ diagnosticEmitter
1674
+ .emitTypedSendingNeverSendableToSendingClosureParamDirectlyIsolated (
1675
+ ce, capture);
1676
+ return true ;
1677
+ }
1678
+ }
1679
+
1680
+ // Ok, we are not tracking an actual isolated value or we do not capture the
1681
+ // isolated value directly... we need to be smarter here. First lets gather up
1682
+ // all non-Sendable values captured by the closure.
1683
+ SmallVector<CapturedValue, 8 > nonSendableCaptures;
1684
+ for (auto capture : ce->getCaptureInfo ().getCaptures ()) {
1685
+ auto *decl = capture.getDecl ();
1686
+ auto type = decl->getInterfaceType ()->getCanonicalType ();
1687
+ auto silType = SILType::getPrimitiveObjectType (type);
1688
+ if (!SILIsolationInfo::isNonSendableType (silType, pai->getFunction ()))
1689
+ continue ;
1690
+
1691
+ auto *fromDC = decl->getInnermostDeclContext ();
1692
+ auto *nom = silType.getNominalOrBoundGenericNominal ();
1693
+ if (nom && fromDC) {
1694
+ if (auto diagnosticBehavior =
1695
+ getConcurrencyDiagnosticBehaviorLimit (nom, fromDC)) {
1696
+ if (*diagnosticBehavior == DiagnosticBehavior::Ignore)
1697
+ continue ;
1698
+ }
1699
+ }
1700
+ nonSendableCaptures.push_back (capture);
1701
+ }
1702
+
1703
+ // If we do not have any non-Sendable captures... bail.
1704
+ if (nonSendableCaptures.empty ())
1705
+ return false ;
1706
+
1707
+ // Otherwise, emit the diagnostic.
1708
+ diagnosticEmitter.emitTypedSendingNeverSendableToSendingClosureParam (
1709
+ ce, nonSendableCaptures);
1710
+ return true ;
1711
+ }
1712
+
1481
1713
bool TransferNonTransferrableDiagnosticInferrer::initForIsolatedPartialApply (
1482
1714
Operand *op, AbstractClosureExpr *ace,
1483
1715
std::optional<ActorIsolation> actualCallerIsolation) {
@@ -1585,6 +1817,11 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
1585
1817
if (auto fas = FullApplySite::isa (op->getUser ())) {
1586
1818
if (fas.getArgumentParameterInfo (*op).hasOption (
1587
1819
SILParameterInfo::Sending)) {
1820
+ // Before we do anything, lets see if we are passing a sendable closure
1821
+ // literal. If we do, we want to emit a special error that states which
1822
+ // captured value caused the actual error.
1823
+ if (initForSendingPartialApply (fas, op))
1824
+ return true ;
1588
1825
1589
1826
// See if we can infer a name from the value.
1590
1827
SmallString<64 > resultingName;
@@ -1724,7 +1961,8 @@ void TransferNonSendableImpl::emitTransferredNonTransferrableDiagnostics() {
1724
1961
llvm::dbgs () << " Emitting transfer non transferrable diagnostics.\n " );
1725
1962
1726
1963
for (auto info : transferredNonTransferrableInfoList) {
1727
- TransferNonTransferrableDiagnosticInferrer diagnosticInferrer (info);
1964
+ TransferNonTransferrableDiagnosticInferrer diagnosticInferrer (
1965
+ regionInfo->getValueMap (), info);
1728
1966
diagnosticInferrer.run ();
1729
1967
}
1730
1968
}
0 commit comments