Skip to content

Commit 59bc23f

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 df7cfbf commit 59bc23f

File tree

2 files changed

+106
-30
lines changed

2 files changed

+106
-30
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7299,15 +7299,38 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
72997299
return RValue();
73007300
}
73017301

7302+
/// getActorIsolationOfContext doesn't return the right isolation for
7303+
/// initializer contexts. Fixing that is a lot of work, so just
7304+
/// hack around it for now here.
7305+
static ActorIsolation getRealActorIsolationOfContext(DeclContext *DC) {
7306+
if (auto init = dyn_cast<Initializer>(DC)) {
7307+
return getActorIsolation(init);
7308+
} else {
7309+
return getActorIsolationOfContext(DC);
7310+
}
7311+
}
7312+
73027313
RValue RValueEmitter::visitCurrentContextIsolationExpr(
73037314
CurrentContextIsolationExpr *E, SGFContext C) {
7304-
auto afd =
7305-
dyn_cast_or_null<AbstractFunctionDecl>(SGF.F.getDeclRef().getDecl());
7306-
if (afd) {
7307-
auto isolation = getActorIsolation(afd);
7308-
auto ctor = dyn_cast_or_null<ConstructorDecl>(afd);
7315+
7316+
auto isolation = getRealActorIsolationOfContext(SGF.FunctionDC);
7317+
7318+
if (isolation == ActorIsolation::CallerIsolationInheriting) {
7319+
auto *isolatedArg = SGF.F.maybeGetIsolatedArgument();
7320+
assert(isolatedArg &&
7321+
"Caller Isolation Inheriting without isolated parameter");
7322+
ManagedValue isolatedMV;
7323+
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
7324+
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
7325+
} else {
7326+
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
7327+
}
7328+
return RValue(SGF, E, isolatedMV);
7329+
}
7330+
7331+
if (isolation == ActorIsolation::ActorInstance) {
7332+
auto ctor = dyn_cast<ConstructorDecl>(SGF.FunctionDC);
73097333
if (ctor && ctor->isDesignatedInit() &&
7310-
isolation == ActorIsolation::ActorInstance &&
73117334
isolation.getActorInstance() == ctor->getImplicitSelfDecl()) {
73127335
// If we are in an actor initializer that is isolated to self, the
73137336
// current isolation is flow-sensitive; use that instead of the
@@ -7316,21 +7339,11 @@ RValue RValueEmitter::visitCurrentContextIsolationExpr(
73167339
SGF.emitFlowSensitiveSelfIsolation(E, isolation);
73177340
return RValue(SGF, E, isolationValue);
73187341
}
7319-
7320-
if (isolation == ActorIsolation::CallerIsolationInheriting) {
7321-
auto *isolatedArg = SGF.F.maybeGetIsolatedArgument();
7322-
assert(isolatedArg &&
7323-
"Caller Isolation Inheriting without isolated parameter");
7324-
ManagedValue isolatedMV;
7325-
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
7326-
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
7327-
} else {
7328-
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
7329-
}
7330-
return RValue(SGF, E, isolatedMV);
7331-
}
73327342
}
73337343

7344+
// Otherwise, just trust the underlying expression. We really don't
7345+
// need to do this at all --- we assume we can produce the isolation
7346+
// value from scratch in other situations --- but whatever.
73347347
return visit(E->getActor(), C);
73357348
}
73367349

test/Concurrency/isolated_nonsending_isolation_macro_sil.swift

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

0 commit comments

Comments
 (0)