Skip to content

Commit 129a021

Browse files
authored
Merge pull request swiftlang#72756 from simanerush/globally-isolated-closures-inference
[Concurrency] Infer `@Sendable` for globally isolated function types and allow globally isolated closures to capture non-`Sendable` values.
2 parents a1d04e6 + 41a8029 commit 129a021

File tree

5 files changed

+41
-7
lines changed

5 files changed

+41
-7
lines changed

include/swift/AST/Types.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3634,9 +3634,7 @@ class AnyFunctionType : public TypeBase {
36343634
return getExtInfo().isNoEscape();
36353635
}
36363636

3637-
bool isSendable() const {
3638-
return getExtInfo().isSendable();
3639-
}
3637+
bool isSendable() const;
36403638

36413639
bool isAsync() const { return getExtInfo().isAsync(); }
36423640

lib/AST/Type.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3895,6 +3895,15 @@ Type AnyFunctionType::getThrownError() const {
38953895
}
38963896
}
38973897

3898+
bool AnyFunctionType::isSendable() const {
3899+
auto &ctx = getASTContext();
3900+
if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability)) {
3901+
// Global-actor-isolated function types are implicitly Sendable.
3902+
return getExtInfo().isSendable() || getIsolation().isGlobalActor();
3903+
}
3904+
return getExtInfo().isSendable();
3905+
}
3906+
38983907
Type AnyFunctionType::getGlobalActor() const {
38993908
switch (getKind()) {
39003909
case TypeKind::Function:

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4181,15 +4181,21 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
41814181
if (useIsolation == defIsolation)
41824182
return false;
41834183

4184+
auto &ctx = useContext->getASTContext();
4185+
bool regionIsolationEnabled =
4186+
ctx.LangOpts.hasFeature(Feature::RegionBasedIsolation);
4187+
4188+
// Globally-isolated closures may never be executed concurrently.
4189+
if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability) &&
4190+
regionIsolationEnabled && useIsolation.isGlobalActor())
4191+
return false;
4192+
41844193
// If the local function is not Sendable, its isolation differs
41854194
// from that of the context, and both contexts are actor isolated,
41864195
// then capturing non-Sendable values allows the closure to stash
41874196
// those values into actor isolated state. The original context
41884197
// may also stash those values into isolated state, enabling concurrent
41894198
// access later on.
4190-
auto &ctx = useContext->getASTContext();
4191-
bool regionIsolationEnabled =
4192-
ctx.LangOpts.hasFeature(Feature::RegionBasedIsolation);
41934199
isolatedStateMayEscape =
41944200
(!regionIsolationEnabled &&
41954201
useIsolation.isActorIsolated() && defIsolation.isActorIsolated());

test/Concurrency/actor_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ extension MyActor {
559559

560560
func testBadImplicitGlobalActorClosureCall() async {
561561
{ @MainActor in }() // expected-error{{expression is 'async' but is not marked with 'await'}}
562-
// expected-note@-1{{calls function of type '@MainActor () -> ()' from outside of its actor context are implicitly asynchronous}}
562+
// expected-note@-1{{calls function of type '@MainActor @Sendable () -> ()' from outside of its actor context are implicitly asynchronous}}
563563
}
564564

565565

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-typecheck-verify-swift -strict-concurrency=complete -disable-availability-checking -enable-upcoming-feature RegionBasedIsolation -enable-experimental-feature GlobalActorIsolatedTypesUsability
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: asserts
5+
6+
func inferSendableFunctionType() {
7+
let closure: @MainActor () -> Void = {}
8+
9+
Task {
10+
await closure() // okay
11+
}
12+
}
13+
14+
class NonSendable {}
15+
16+
func allowNonSendableCaptures() {
17+
let nonSendable = NonSendable()
18+
let _: @MainActor () -> Void = {
19+
let _ = nonSendable // okay
20+
}
21+
}

0 commit comments

Comments
 (0)