Skip to content

Commit f841fa0

Browse files
committed
[Concurrency] Don't allow erasing global actor isolation when the function
value crosses an isolation boundary.
1 parent 298346f commit f841fa0

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,7 +1917,7 @@ bool swift::isAsyncDecl(ConcreteDeclRef declRef) {
19171917
/// \param ty a function type where \c globalActor was removed from it.
19181918
/// \return true if it is safe to drop the global-actor qualifier.
19191919
static bool safeToDropGlobalActor(
1920-
DeclContext *dc, Type globalActor, Type ty) {
1920+
DeclContext *dc, Type globalActor, Type ty, ApplyExpr *call) {
19211921
auto funcTy = ty->getAs<AnyFunctionType>();
19221922
if (!funcTy)
19231923
return false;
@@ -1942,6 +1942,11 @@ static bool safeToDropGlobalActor(
19421942
if (funcTy->isAsync())
19431943
return true;
19441944

1945+
// If the argument is passed over an isolation boundary, it's not
1946+
// safe to erase actor isolation, because the caller
1947+
if (call && call->getIsolationCrossing())
1948+
return false;
1949+
19451950
// fundamentally cannot be sendable if we want to drop isolation info
19461951
if (funcTy->isSendable())
19471952
return false;
@@ -2364,7 +2369,8 @@ namespace {
23642369
return;
23652370

23662371
auto dc = const_cast<DeclContext*>(getDeclContext());
2367-
if (!safeToDropGlobalActor(dc, fromActor, toType)) {
2372+
if (!safeToDropGlobalActor(dc, fromActor, toType,
2373+
getImmediateApply())) {
23682374
// otherwise, it's not a safe cast.
23692375
dc->getASTContext()
23702376
.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)