Skip to content

Commit 367520c

Browse files
committed
Fix two bugs with the isolation of defer bodies.
The first bug is that we weren't computing isolation correctly for nested defers. This is an unlikely pattern of code, but it's good to fix. The second bug is that getActorIsolationOfContext was looking through defers, but getActorIsolation itself was not. This was causing defer bodies to be emitted in SILGen without an isolation parameter, which meant that #isolation could not possibly provide the right value. Fixing this involves teaching SILGen that non-async functions can have nonisolated(nonsending) isolation, but that's relatively straightforward. This commit doesn't fix #isolation or adequately test SILGen, but that'll be handled in a follow-up.
1 parent 5fb314b commit 367520c

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,6 +3285,9 @@ class ValueDecl : public Decl {
32853285
/// `AbstractStorageDecl`, returns `false`.
32863286
bool isAsync() const;
32873287

3288+
/// Returns whether this function represents a defer body.
3289+
bool isDeferBody() const;
3290+
32883291
private:
32893292
bool isObjCDynamic() const {
32903293
return isObjC() && isDynamic();

lib/AST/Decl.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11879,6 +11879,12 @@ PrecedenceGroupDecl *InfixOperatorDecl::getPrecedenceGroup() const {
1187911879
nullptr);
1188011880
}
1188111881

11882+
bool ValueDecl::isDeferBody() const {
11883+
if (auto fn = dyn_cast<FuncDecl>(this))
11884+
return fn->isDeferBody();
11885+
return false;
11886+
}
11887+
1188211888
bool FuncDecl::isDeferBody() const {
1188311889
return getBaseIdentifier() == getASTContext().getIdentifier("$defer");
1188411890
}
@@ -12072,12 +12078,16 @@ ActorIsolation swift::getActorIsolationOfContext(
1207212078
getClosureActorIsolation) {
1207312079
auto &ctx = dc->getASTContext();
1207412080
auto dcToUse = dc;
12075-
// Defer bodies share actor isolation of their enclosing context.
12076-
if (auto FD = dyn_cast<FuncDecl>(dcToUse)) {
12077-
if (FD->isDeferBody()) {
12078-
dcToUse = FD->getDeclContext();
12079-
}
12081+
12082+
// Defer bodies share the actor isolation of their enclosing context.
12083+
// We don't actually have to do this check here because
12084+
// getActorIsolation does consider it already, but it's nice to
12085+
// avoid some extra request evaluation in a trivial case.
12086+
while (auto FD = dyn_cast<FuncDecl>(dcToUse)) {
12087+
if (!FD->isDeferBody()) break;
12088+
dcToUse = FD->getDeclContext();
1208012089
}
12090+
1208112091
if (auto *vd = dyn_cast_or_null<ValueDecl>(dcToUse->getAsDecl()))
1208212092
return getActorIsolation(vd);
1208312093

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6353,6 +6353,14 @@ static bool shouldSelfIsolationOverrideDefault(
63536353

63546354
static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
63556355
ValueDecl *value) {
6356+
// Defer bodies share the actor isolation of their enclosing context.
6357+
if (value->isDeferBody()) {
6358+
return {
6359+
getActorIsolationOfContext(value->getDeclContext()),
6360+
IsolationSource()
6361+
};
6362+
}
6363+
63566364
// If this declaration has actor-isolated "self", it's isolated to that
63576365
// actor.
63586366
if (evaluateOrDefault(evaluator, HasIsolatedSelfRequest{value}, false)) {

test/Concurrency/actor_defer.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ func testNonDefer_negative() {
3636
// CHECK-NEXT: function_ref
3737
// CHECK-NEXT: apply
3838

39+
@MainActor func testGlobalActor_nested_positive() {
40+
defer {
41+
defer {
42+
requiresMainActor()
43+
}
44+
doSomething()
45+
}
46+
doSomething()
47+
}
48+
3949
#if NEGATIVES
4050
// expected-note @+1 {{add '@MainActor' to make global function 'testGlobalActor_negative()' part of global actor 'MainActor'}}
4151
func testGlobalActor_negative() {

0 commit comments

Comments
 (0)