Skip to content

Commit bb339b8

Browse files
authored
Merge pull request swiftlang#72865 from hborla/6.0-unsafe-isolation-erasure
[6.0][Concurrency] Don't allow erasing global actor isolation when the function value crosses an isolation boundary.
2 parents 1f723d4 + 0073042 commit bb339b8

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,7 @@ bool swift::isAsyncDecl(ConcreteDeclRef declRef) {
19031903
/// \param ty a function type where \c globalActor was removed from it.
19041904
/// \return true if it is safe to drop the global-actor qualifier.
19051905
static bool safeToDropGlobalActor(
1906-
DeclContext *dc, Type globalActor, Type ty) {
1906+
DeclContext *dc, Type globalActor, Type ty, ApplyExpr *call) {
19071907
auto funcTy = ty->getAs<AnyFunctionType>();
19081908
if (!funcTy)
19091909
return false;
@@ -1928,6 +1928,12 @@ static bool safeToDropGlobalActor(
19281928
if (funcTy->isAsync())
19291929
return true;
19301930

1931+
// If the argument is passed over an isolation boundary, it's not
1932+
// safe to erase actor isolation, because the callee can call the
1933+
// function synchronously from outside the isolation domain.
1934+
if (call && call->getIsolationCrossing())
1935+
return false;
1936+
19311937
// fundamentally cannot be sendable if we want to drop isolation info
19321938
if (funcTy->isSendable())
19331939
return false;
@@ -2350,7 +2356,8 @@ namespace {
23502356
return;
23512357

23522358
auto dc = const_cast<DeclContext*>(getDeclContext());
2353-
if (!safeToDropGlobalActor(dc, fromActor, toType)) {
2359+
if (!safeToDropGlobalActor(dc, fromActor, toType,
2360+
getImmediateApply())) {
23542361
// otherwise, it's not a safe cast.
23552362
dc->getASTContext()
23562363
.Diags

test/Concurrency/actor_isolation.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ actor Crystal {
468468
await asyncGlobalActorFunc()
469469
}
470470

471+
func crossIsolationBoundary(_ closure: () -> Void) async {}
472+
471473
@available(SwiftStdlib 5.1, *)
472474
func testGlobalActorClosures() {
473475
let _: Int = acceptAsyncClosure { @SomeGlobalActor in
@@ -480,6 +482,15 @@ func testGlobalActorClosures() {
480482
}
481483

482484
acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-warning {{converting function value of type '@SomeGlobalActor @Sendable () -> Int' to '@Sendable () -> Int' loses global actor 'SomeGlobalActor'}}
485+
486+
@MainActor func test() async {
487+
let closure = { @MainActor @Sendable in
488+
MainActor.assertIsolated()
489+
}
490+
491+
await crossIsolationBoundary(closure)
492+
// expected-warning@-1 {{converting function value of type '@MainActor @Sendable () -> ()' to '() -> Void' loses global actor 'MainActor'; this is an error in the Swift 6 language mode}}
493+
}
483494
}
484495

485496
@available(SwiftStdlib 5.1, *)

0 commit comments

Comments
 (0)