Skip to content

Commit 995e9e0

Browse files
authored
Merge pull request #79164 from gottesmm/release/6.1-rdar138667211
[6.1] Fix some type issues around handling closures in SendNonSendable
2 parents 75f707b + 538823a commit 995e9e0

File tree

4 files changed

+70
-17
lines changed

4 files changed

+70
-17
lines changed

include/swift/SILOptimizer/Utils/SILIsolationInfo.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,17 +434,21 @@ class SILIsolationInfo {
434434
return {};
435435
}
436436

437+
static bool isNonSendableType(SILType type, SILFunction *fn) {
438+
return isNonSendableType(type.getASTType(), fn);
439+
}
440+
441+
static bool isNonSendableType(SILValue value) {
442+
return isNonSendableType(value->getType(), value->getFunction());
443+
}
444+
437445
/// A helper that is used to ensure that we treat certain builtin values as
438446
/// non-Sendable that the AST level otherwise thinks are non-Sendable.
439447
///
440448
/// E.x.: Builtin.RawPointer and Builtin.NativeObject
441449
///
442450
/// TODO: Fix the type checker.
443-
static bool isNonSendableType(SILType type, SILFunction *fn);
444-
445-
static bool isNonSendableType(SILValue value) {
446-
return isNonSendableType(value->getType(), value->getFunction());
447-
}
451+
static bool isNonSendableType(CanType type, SILFunction *fn);
448452

449453
bool hasSameIsolation(ActorIsolation actorIsolation) const;
450454

lib/SILOptimizer/Mandatory/SendNonSendable.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,18 +1661,31 @@ bool SentNeverSendableDiagnosticInferrer::initForSendingPartialApply(
16611661
}
16621662

16631663
// Ok, we are not tracking an actual isolated value or we do not capture the
1664-
// isolated value directly... we need to be smarter here. First lets gather up
1665-
// all non-Sendable values captured by the closure.
1664+
// isolated value directly, we instead just emit a note on all the potential
1665+
// non-Sendable captures.
1666+
1667+
// First grab the calleeFunction of the closure so we can properly map our
1668+
// captured types into the closure's context so that we can determine
1669+
// non-Sendability.
1670+
auto *calleeFunction = pai->getCalleeFunction();
1671+
if (!calleeFunction) {
1672+
// We should always be able to find a callee function for a partial_apply
1673+
// created from a closure expr. If we don't, we want to flag this as an
1674+
// error to be reported.
1675+
diagnosticEmitter.emitUnknownPatternError();
1676+
return true;
1677+
}
1678+
16661679
SmallVector<CapturedValue, 8> nonSendableCaptures;
16671680
for (auto capture : ce->getCaptureInfo().getCaptures()) {
16681681
auto *decl = capture.getDecl();
16691682
auto type = decl->getInterfaceType()->getCanonicalType();
1670-
auto silType = SILType::getPrimitiveObjectType(type);
1671-
if (!SILIsolationInfo::isNonSendableType(silType, pai->getFunction()))
1683+
type = calleeFunction->mapTypeIntoContext(type)->getCanonicalType();
1684+
if (!SILIsolationInfo::isNonSendableType(type, calleeFunction))
16721685
continue;
16731686

16741687
auto *fromDC = decl->getInnermostDeclContext();
1675-
auto *nom = silType.getNominalOrBoundGenericNominal();
1688+
auto *nom = type.getNominalOrBoundGenericNominal();
16761689
if (nom && fromDC) {
16771690
if (auto diagnosticBehavior =
16781691
getConcurrencyDiagnosticBehaviorLimit(nom, fromDC)) {

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,18 +1215,18 @@ void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const {
12151215
//
12161216
// NOTE: We special case RawPointer and NativeObject to ensure they are
12171217
// treated as non-Sendable and strict checking is applied to it.
1218-
bool SILIsolationInfo::isNonSendableType(SILType type, SILFunction *fn) {
1218+
bool SILIsolationInfo::isNonSendableType(CanType type, SILFunction *fn) {
12191219
// Treat Builtin.NativeObject, Builtin.RawPointer, and Builtin.BridgeObject as
12201220
// non-Sendable.
1221-
if (type.getASTType()->is<BuiltinNativeObjectType>() ||
1222-
type.getASTType()->is<BuiltinRawPointerType>() ||
1223-
type.getASTType()->is<BuiltinBridgeObjectType>()) {
1221+
if (type->is<BuiltinNativeObjectType>() ||
1222+
type->is<BuiltinRawPointerType>() ||
1223+
type->is<BuiltinBridgeObjectType>()) {
12241224
return true;
12251225
}
12261226

12271227
// Treat Builtin.SILToken as Sendable. It cannot escape from the current
12281228
// function. We should change isSendable to hardwire this.
1229-
if (type.getASTType()->is<SILTokenType>()) {
1229+
if (type->is<SILTokenType>()) {
12301230
return false;
12311231
}
12321232

@@ -1237,12 +1237,17 @@ bool SILIsolationInfo::isNonSendableType(SILType type, SILFunction *fn) {
12371237
// getConcurrencyDiagnosticBehavior could cause us to prevent a
12381238
// "preconcurrency" unneeded diagnostic when just using Sendable values. We
12391239
// only want to trigger that if we analyze a non-Sendable type.
1240-
if (type.isSendable(fn))
1240+
if (type->isSendableType())
12411241
return false;
12421242

12431243
// Grab out behavior. If it is none, then we have a type that we want to treat
12441244
// as non-Sendable.
1245-
auto behavior = type.getConcurrencyDiagnosticBehavior(fn);
1245+
auto declRef = fn->getDeclRef();
1246+
if (!declRef)
1247+
return true;
1248+
1249+
auto *fromDC = declRef.getInnermostDeclContext();
1250+
auto behavior = type->getConcurrencyDiagnosticBehaviorLimit(fromDC);
12461251
if (!behavior)
12471252
return true;
12481253

test/Concurrency/transfernonsendable.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,3 +1906,34 @@ func offByOneWithImplicitPartialApply() {
19061906
}
19071907
}
19081908
}
1909+
1910+
protocol Progress { // expected-note {{}}
1911+
associatedtype AssocType
1912+
var x: AssocType { get }
1913+
func checkCancellation() throws
1914+
}
1915+
1916+
// We used to crash here since the closure diagnostic would not map z's type
1917+
// into the current context.
1918+
func testCaptureDiagnosticMapsTypeIntoContext<T : Progress>(_ x: NonSendableKlass, y: T) async throws {
1919+
let z = y.x
1920+
await withTaskGroup(of: Void.self) { group in
1921+
group.addTask { // expected-tns-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
1922+
print(z) // expected-tns-note {{closure captures 'z' which is accessible to code in the current task}}
1923+
}
1924+
}
1925+
}
1926+
1927+
// We used to crash here since we were using an API that wanted a SIL Type and
1928+
// we were creating a SILType from a CanType that needed to be lowered.
1929+
func testUseCanTypeNonSendableCheckAPI(y: any Progress) async {
1930+
@Sendable func test() {
1931+
print(y) // expected-warning {{capture of 'y' with non-sendable type 'any Progress' in a '@Sendable' local function}}
1932+
}
1933+
await withTaskGroup(of: Void.self) { group in
1934+
group.addTask { // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
1935+
// expected-tns-note @-1 {{Passing task-isolated value of non-Sendable type '() async -> ()' as a 'sending' parameter risks causing races inbetween task-isolated uses and uses reachable from the callee}}
1936+
test()
1937+
}
1938+
}
1939+
}

0 commit comments

Comments
 (0)