Skip to content

Commit 8301d53

Browse files
committed
Fix the evaluation of #isolation in non-AFD contexts, most importantly
closures. The fixes for initializers are just setting the stage for doing this properly: we should be able to just change the isolation computation in Sema and fix up the tests.
1 parent c7cad4b commit 8301d53

File tree

2 files changed

+98
-19
lines changed

2 files changed

+98
-19
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7393,15 +7393,38 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
73937393
return RValue();
73947394
}
73957395

7396+
/// getActorIsolationOfContext doesn't return the right isolation for
7397+
/// initializer contexts. Fixing that is a lot of work, so just
7398+
/// hack around it for now here.
7399+
static ActorIsolation getRealActorIsolationOfContext(DeclContext *DC) {
7400+
if (auto init = dyn_cast<Initializer>(DC)) {
7401+
return getActorIsolation(init);
7402+
} else {
7403+
return getActorIsolationOfContext(DC);
7404+
}
7405+
}
7406+
73967407
RValue RValueEmitter::visitCurrentContextIsolationExpr(
73977408
CurrentContextIsolationExpr *E, SGFContext C) {
7398-
auto afd =
7399-
dyn_cast_or_null<AbstractFunctionDecl>(SGF.F.getDeclRef().getDecl());
7400-
if (afd) {
7401-
auto isolation = getActorIsolation(afd);
7402-
auto ctor = dyn_cast_or_null<ConstructorDecl>(afd);
7409+
7410+
auto isolation = getRealActorIsolationOfContext(SGF.FunctionDC);
7411+
7412+
if (isolation == ActorIsolation::CallerIsolationInheriting) {
7413+
auto *isolatedArg = SGF.F.maybeGetIsolatedArgument();
7414+
assert(isolatedArg &&
7415+
"Caller Isolation Inheriting without isolated parameter");
7416+
ManagedValue isolatedMV;
7417+
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
7418+
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
7419+
} else {
7420+
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
7421+
}
7422+
return RValue(SGF, E, isolatedMV);
7423+
}
7424+
7425+
if (isolation == ActorIsolation::ActorInstance) {
7426+
auto ctor = dyn_cast<ConstructorDecl>(SGF.FunctionDC);
74037427
if (ctor && ctor->isDesignatedInit() &&
7404-
isolation == ActorIsolation::ActorInstance &&
74057428
isolation.getActorInstance() == ctor->getImplicitSelfDecl()) {
74067429
// If we are in an actor initializer that is isolated to self, the
74077430
// current isolation is flow-sensitive; use that instead of the
@@ -7410,21 +7433,11 @@ RValue RValueEmitter::visitCurrentContextIsolationExpr(
74107433
SGF.emitFlowSensitiveSelfIsolation(E, isolation);
74117434
return RValue(SGF, E, isolationValue);
74127435
}
7413-
7414-
if (isolation == ActorIsolation::CallerIsolationInheriting) {
7415-
auto *isolatedArg = SGF.F.maybeGetIsolatedArgument();
7416-
assert(isolatedArg &&
7417-
"Caller Isolation Inheriting without isolated parameter");
7418-
ManagedValue isolatedMV;
7419-
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
7420-
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
7421-
} else {
7422-
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
7423-
}
7424-
return RValue(SGF, E, isolatedMV);
7425-
}
74267436
}
74277437

7438+
// Otherwise, just trust the underlying expression. We really don't
7439+
// need to do this at all --- we assume we can produce the isolation
7440+
// value from scratch in other situations --- but whatever.
74287441
return visit(E->getActor(), C);
74297442
}
74307443

test/Concurrency/isolated_nonsending_isolation_macro_sil.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,69 @@ func take(iso: (any Actor)?) {}
1919
// CHECK: apply [[FUNC]]([[ACTOR]]) : $@convention(thin) (@guaranteed Optional<any Actor>) -> ()
2020
// CHECK: release_value [[ACTOR]]
2121
// CHECK: } // end sil function '$s39isolated_nonsending_isolation_macro_sil21nonisolatedNonsendingyyYaF'
22+
23+
// Check that we emit #isolation correctly in closures.
24+
// CHECK-LABEL: // closure #1 in containsClosure()
25+
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
26+
// CHECK: bb0(%0 : $Optional<any Actor>):
27+
// CHECK-NEXT: // function_ref take(iso:)
28+
// CHECK-NEXT: [[FN:%.*]] = function_ref @
29+
// CHECK-NEXT: apply [[FN]](%0)
30+
func containsClosure() {
31+
let closure: nonisolated(nonsending) () async -> Void = {
32+
take(iso: #isolation)
33+
}
34+
}
35+
36+
// Check that we emit #isolation correctly in defer bodies.
37+
nonisolated(nonsending)
38+
func hasDefer() async {
39+
defer {
40+
take(iso: #isolation)
41+
}
42+
do {}
43+
}
44+
// CHECK-LABEL: sil hidden @$s39isolated_nonsending_isolation_macro_sil8hasDeferyyYaF :
45+
// CHECK: bb0(%0 : $Optional<any Actor>):
46+
// CHECK: // function_ref $defer
47+
// CHECK-NEXT: [[DEFER:%.*]] = function_ref
48+
// CHECK-NEXT: apply [[DEFER]](%0)
49+
50+
// CHECK-LABEL: // $defer #1 () in hasDefer()
51+
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
52+
// CHECK: bb0(%0 : $Optional<any Actor>):
53+
// CHECK-NEXT: // function_ref take(iso:)
54+
// CHECK-NEXT: [[FN:%.*]] = function_ref @
55+
// CHECK-NEXT: apply [[FN]](%0)
56+
57+
// Check that we emit #isolation correctly in nested defer bodies.
58+
nonisolated(nonsending)
59+
func hasNestedDefer() async {
60+
defer {
61+
defer {
62+
take(iso: #isolation)
63+
}
64+
do {}
65+
}
66+
do {}
67+
}
68+
69+
// CHECK-LABEL: sil hidden @$s39isolated_nonsending_isolation_macro_sil14hasNestedDeferyyYaF :
70+
// CHECK: bb0(%0 : $Optional<any Actor>):
71+
// CHECK: // function_ref $defer #1 () in hasNestedDefer()
72+
// CHECK-NEXT: [[DEFER:%.*]] = function_ref
73+
// CHECK-NEXT: apply [[DEFER]](%0)
74+
75+
// CHECK-LABEL: // $defer #1 () in hasNestedDefer()
76+
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
77+
// CHECK: bb0(%0 : $Optional<any Actor>):
78+
// CHECK: // function_ref $defer #1 () in $defer #1 () in hasNestedDefer()
79+
// CHECK-NEXT: [[DEFER:%.*]] = function_ref
80+
// CHECK-NEXT: apply [[DEFER]](%0)
81+
82+
// CHECK-LABEL: // $defer #1 () in $defer #1 () in hasNestedDefer()
83+
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
84+
// CHECK: bb0(%0 : $Optional<any Actor>):
85+
// CHECK-NEXT: // function_ref take(iso:)
86+
// CHECK-NEXT: [[FN:%.*]] = function_ref @
87+
// CHECK-NEXT: apply [[FN]](%0)

0 commit comments

Comments
 (0)