Skip to content

Commit 9cdb8d1

Browse files
committed
[Concurrency] Fix @_inheritActorContext(always) to use forActorInstanceCapture for parameters
SILGen expects actor instance isolation to always come from captures, we need to maintain that with implicit isolation capture performed by `@_inheritActorContext(always)`. (cherry picked from commit 9104744)
1 parent 5f7b990 commit 9cdb8d1

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4799,13 +4799,18 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
47994799

48004800
case ActorIsolation::ActorInstance: {
48014801
if (checkIsolatedCapture) {
4802+
if (auto param = closure->getCaptureInfo().getIsolatedParamCapture())
4803+
return ActorIsolation::forActorInstanceCapture(param);
4804+
48024805
auto *explicitClosure = dyn_cast<ClosureExpr>(closure);
48034806
// @_inheritActorContext(always) forces the isolation capture.
4804-
if (explicitClosure && explicitClosure->alwaysInheritsActorContext())
4807+
if (explicitClosure && explicitClosure->alwaysInheritsActorContext()) {
4808+
if (parentIsolation.isActorInstanceIsolated()) {
4809+
if (auto *param = parentIsolation.getActorInstance())
4810+
return ActorIsolation::forActorInstanceCapture(param);
4811+
}
48054812
return parentIsolation;
4806-
4807-
if (auto param = closure->getCaptureInfo().getIsolatedParamCapture())
4808-
return ActorIsolation::forActorInstanceCapture(param);
4813+
}
48094814
} else {
48104815
// If we don't have capture information during code completion, assume
48114816
// that the closure captures the `isolated` parameter from the parent

test/SILGen/hop_to_executor.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ func testGlobalActorFuncValue(_ fn: @RedActor () -> Void) async {
325325

326326
func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable () async -> T) { }
327327
func acceptAsyncSendableClosureAlwaysInheriting<T>(@_inheritActorContext(always) _: @Sendable () async -> T) { }
328+
func acceptAsyncSendableClosureAlwaysInheritingErased<T>(@_inheritActorContext(always) _: sending @isolated(any) () async -> T) { }
328329

329330
extension MyActor {
330331
func synchronous() { }
@@ -385,6 +386,22 @@ func testIsolatedParameterWithInheritActorContext(_ isolation: isolated (any Act
385386
}
386387
}
387388

389+
// CHECK-LABEL: sil hidden [ossa] @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiF
390+
// CHECK: [[CLOSURE_REF:%.*]] = function_ref @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiFyyYaXEfU_
391+
// CHECK-NEXT: [[ISOLATION_COPY_1:%.*]] = copy_value %0 : $any Actor
392+
// CHECK-NEXT: [[ISOLATION_COPY_2:%.*]] = copy_value [[ISOLATION_COPY_1]] : $any Actor
393+
// CHECK-NEXT: [[DYNAMIC_ISOLATION:%.*]] = enum $Optional<any Actor>, #Optional.some!enumelt, [[ISOLATION_COPY_2]] : $any Actor
394+
// CHECK-NEXT: [[CLOSURE_WITH_APPLIED_ISOLATION:%.*]] = partial_apply [callee_guaranteed] [isolated_any] [[CLOSURE_REF]]([[DYNAMIC_ISOLATION]], [[ISOLATION_COPY_1]])
395+
func testIsolatedParamWithIsolatedAny(_ isolation: isolated any Actor) {
396+
// CHECK-LABEL: sil private [ossa] @$s4test0a17IsolatedParamWithB3AnyyyScA_pYiFyyYaXEfU_
397+
// CHECK: bb0(%0 : $*(), [[DYNAMIC_ISOLATION:%[0-9]+]] : @guaranteed $Optional<any Actor>, [[CAPTURED_ISOLATION:%[0-9]+]] : @closureCapture @guaranteed $any Actor):
398+
// CHECK: [[COPY:%[0-9]+]] = copy_value [[CAPTURED_ISOLATION]] : $any Actor
399+
// CHECK-NEXT: [[BORROW:%[0-9]+]] = begin_borrow [[COPY]] : $any Actor
400+
// CHECK-NEXT: hop_to_executor [[BORROW]] : $any Actor
401+
acceptAsyncSendableClosureAlwaysInheritingErased {
402+
}
403+
}
404+
388405
func acceptAsyncClosure(_: () async -> Void) { }
389406
func acceptAsyncClosure2<T>(_: (T) async -> T) { }
390407

0 commit comments

Comments
 (0)