Skip to content

Commit 1f9e302

Browse files
gottesmmxedin
authored andcommitted
[rbi] Teach SendNonSendable how to more aggressively suppress sending errors around obfuscated Sendable functions
Specifically the type checker to work around interface types not having isolation introduces casts into the AST that enrich the AST with isolation information. Part of that information is Sendable. This means that we can sometimes lose due to conversions that a function is actually Sendable. To work around this, we today suppress those errors when they are emitted (post 6.2, we should just change their classification as being Sendable... but I don't want to make that change now). This change just makes the pattern matching for these conversions handle more cases so that transfernonsendable_closureliterals_isolationinference.swift now passes.
1 parent 35c3b9e commit 1f9e302

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,9 +1598,32 @@ struct PartitionOpEvaluator {
15981598
}
15991599

16001600
private:
1601-
bool isConvertFunctionFromSendableType(SILValue equivalenceClassRep) const {
1601+
/// To work around not having isolation in interface types, the type checker
1602+
/// inserts casts and other AST nodes that are used to enrich the AST with
1603+
/// isolation information. This results in Sendable functions being
1604+
/// wrapped/converted/etc in ways that hide the Sendability. This helper looks
1605+
/// through these conversions/wrappers/thunks to see if the original
1606+
/// underlying function is Sendable.
1607+
///
1608+
/// The two ways this can happen is that we either get an actual function_ref
1609+
/// that is Sendable or we get a convert function with a Sendable operand.
1610+
bool isHiddenSendableFunctionType(SILValue equivalenceClassRep) const {
16021611
SILValue valueToTest = equivalenceClassRep;
16031612
while (true) {
1613+
if (auto *pai = dyn_cast<PartialApplyInst>(valueToTest)) {
1614+
if (auto *calleeFunction = pai->getCalleeFunction()) {
1615+
if (pai->getNumArguments() >= 1 &&
1616+
pai->getArgument(0)->getType().isFunction() &&
1617+
calleeFunction->isThunk()) {
1618+
valueToTest = pai->getArgument(0);
1619+
continue;
1620+
}
1621+
1622+
if (calleeFunction->getLoweredFunctionType()->isSendable())
1623+
return true;
1624+
}
1625+
}
1626+
16041627
if (auto *i = dyn_cast<ThinToThickFunctionInst>(valueToTest)) {
16051628
valueToTest = i->getOperand();
16061629
continue;
@@ -1612,6 +1635,9 @@ struct PartitionOpEvaluator {
16121635
break;
16131636
}
16141637

1638+
if (auto *fn = dyn_cast<FunctionRefInst>(valueToTest))
1639+
return fn->getReferencedFunction()->getLoweredFunctionType()->isSendable();
1640+
16151641
auto *cvi = dyn_cast<ConvertFunctionInst>(valueToTest);
16161642
if (!cvi)
16171643
return false;
@@ -1644,7 +1670,7 @@ struct PartitionOpEvaluator {
16441670

16451671
// See if we have a convert function from a `@Sendable` type. In this
16461672
// case, we want to squelch the error.
1647-
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1673+
if (isHiddenSendableFunctionType(equivalenceClassRep))
16481674
return;
16491675
}
16501676

@@ -1689,7 +1715,7 @@ struct PartitionOpEvaluator {
16891715

16901716
// See if we have a convert function from a `@Sendable` type. In this
16911717
// case, we want to squelch the error.
1692-
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1718+
if (isHiddenSendableFunctionType(equivalenceClassRep))
16931719
return;
16941720
}
16951721
}

test/Concurrency/transfernonsendable_global_actor_sending.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ func useValue<T>(_ t: T) {}
3434
@MainActor func testGlobalFakeInit() {
3535
let ns = NonSendableKlass()
3636

37-
// Will be resolved once @MainActor is @Sendable.
38-
Task.fakeInit { @MainActor in // expected-error {{passing closure as a 'sending' parameter risks causing data races between main actor-isolated code and concurrent execution of the closure}}
39-
print(ns) // expected-note {{closure captures 'ns' which is accessible to main actor-isolated code}}
37+
Task.fakeInit { @MainActor in
38+
print(ns)
4039
}
4140

4241
useValue(ns)

0 commit comments

Comments
 (0)