@@ -58,6 +58,29 @@ using Region = PartitionPrimitives::Region;
5858// MARK: Utilities
5959// ===----------------------------------------------------------------------===//
6060
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+
6184static std::optional<DiagnosticBehavior>
6285getDiagnosticBehaviorLimitForValue (SILValue value) {
6386 auto *nom = value->getType ().getNominalOrBoundGenericNominal ();
@@ -72,6 +95,38 @@ getDiagnosticBehaviorLimitForValue(SILValue value) {
7295 return getConcurrencyDiagnosticBehaviorLimit (nom, fromDC);
7396}
7497
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+
75130static std::optional<SILDeclRef> getDeclRefForCallee (SILInstruction *inst) {
76131 auto fas = FullApplySite::isa (inst);
77132 if (!fas)
@@ -1318,6 +1373,98 @@ class TransferNonTransferrableDiagnosticEmitter {
13181373 .limitBehaviorIf (getBehaviorLimit ());
13191374 }
13201375
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+
13211468 void emitNamedOnlyError (SILLocation loc, Identifier name) {
13221469 diagnoseError (loc, diag::regionbasedisolation_named_transfer_yields_race,
13231470 name)
@@ -1455,12 +1602,13 @@ class TransferNonTransferrableDiagnosticEmitter {
14551602class TransferNonTransferrableDiagnosticInferrer {
14561603 struct AutoClosureWalker ;
14571604
1605+ RegionAnalysisValueMap &valueMap;
14581606 TransferNonTransferrableDiagnosticEmitter diagnosticEmitter;
14591607
14601608public:
14611609 TransferNonTransferrableDiagnosticInferrer (
1462- TransferredNonTransferrableInfo info)
1463- : diagnosticEmitter(info) {}
1610+ RegionAnalysisValueMap &valueMap, TransferredNonTransferrableInfo info)
1611+ : valueMap(valueMap), diagnosticEmitter(info) {}
14641612
14651613 // / Gathers diagnostics. Returns false if we emitted a "I don't understand
14661614 // / error". If we emit such an error, we should bail without emitting any
@@ -1474,10 +1622,94 @@ class TransferNonTransferrableDiagnosticInferrer {
14741622 bool initForIsolatedPartialApply (
14751623 Operand *op, AbstractClosureExpr *ace,
14761624 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+ }
14771644};
14781645
14791646} // namespace
14801647
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+
14811713bool TransferNonTransferrableDiagnosticInferrer::initForIsolatedPartialApply (
14821714 Operand *op, AbstractClosureExpr *ace,
14831715 std::optional<ActorIsolation> actualCallerIsolation) {
@@ -1585,6 +1817,11 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
15851817 if (auto fas = FullApplySite::isa (op->getUser ())) {
15861818 if (fas.getArgumentParameterInfo (*op).hasOption (
15871819 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 ;
15881825
15891826 // See if we can infer a name from the value.
15901827 SmallString<64 > resultingName;
@@ -1724,7 +1961,8 @@ void TransferNonSendableImpl::emitTransferredNonTransferrableDiagnostics() {
17241961 llvm::dbgs () << " Emitting transfer non transferrable diagnostics.\n " );
17251962
17261963 for (auto info : transferredNonTransferrableInfoList) {
1727- TransferNonTransferrableDiagnosticInferrer diagnosticInferrer (info);
1964+ TransferNonTransferrableDiagnosticInferrer diagnosticInferrer (
1965+ regionInfo->getValueMap (), info);
17281966 diagnosticInferrer.run ();
17291967 }
17301968}
0 commit comments