Skip to content

Revert "[5.7🍒][Concurrency] Handle actor isolation for defers in closures" #61012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9140,20 +9140,14 @@ ActorIsolation swift::getActorIsolation(ValueDecl *value) {
}

ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
auto dcToUse = dc;
// Defer bodies share actor isolation of their enclosing context.
if (auto FD = dyn_cast<FuncDecl>(dcToUse)) {
if (FD->isDeferBody()) {
dcToUse = FD->getDeclContext();
}
}
if (auto *vd = dyn_cast_or_null<ValueDecl>(dcToUse->getAsDecl()))
if (auto *vd = dyn_cast_or_null<ValueDecl>(dc->getAsDecl()))
return getActorIsolation(vd);

if (auto *var = dcToUse->getNonLocalVarDecl())
return getActorIsolation(var);
if (auto *var = dc->getNonLocalVarDecl())
return getActorIsolation(var);


if (auto *closure = dyn_cast<AbstractClosureExpr>(dcToUse)) {
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {
switch (auto isolation = closure->getActorIsolation()) {
case ClosureActorIsolation::Independent:
return ActorIsolation::forIndependent()
Expand All @@ -9176,14 +9170,14 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
}
}

if (auto *tld = dyn_cast<TopLevelCodeDecl>(dcToUse)) {
if (dcToUse->isAsyncContext() ||
dcToUse->getASTContext().LangOpts.StrictConcurrencyLevel >=
StrictConcurrency::Complete) {
if (Type mainActor = dcToUse->getASTContext().getMainActorType())
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
if (dc->isAsyncContext() ||
dc->getASTContext().LangOpts.StrictConcurrencyLevel
>= StrictConcurrency::Complete) {
if (Type mainActor = dc->getASTContext().getMainActorType())
return ActorIsolation::forGlobalActor(
mainActor,
/*unsafe=*/!dcToUse->getASTContext().isSwiftVersionAtLeast(6));
/*unsafe=*/!dc->getASTContext().isSwiftVersionAtLeast(6));
}
}

Expand Down
9 changes: 8 additions & 1 deletion lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,7 +1489,6 @@ static FuncDecl *findAnnotatableFunction(DeclContext *dc) {
}

/// Note when the enclosing context could be put on a global actor.
// FIXME: This should handle closures too.
static void noteGlobalActorOnContext(DeclContext *dc, Type globalActor) {
// If we are in a synchronous function on the global actor,
// suggest annotating with the global actor itself.
Expand Down Expand Up @@ -3756,6 +3755,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
// If this is a local function, inherit the actor isolation from its
// context if it global or was captured.
if (auto func = dyn_cast<FuncDecl>(value)) {
// If this is a defer body, inherit unconditionally; we don't
// care if the enclosing function captures the isolated parameter.
if (func->isDeferBody()) {
auto enclosingIsolation =
getActorIsolationOfContext(func->getDeclContext());
return inferredIsolation(enclosingIsolation);
}

if (func->isLocalCapture() && !func->isSendable()) {
switch (auto enclosingIsolation =
getActorIsolationOfContext(func->getDeclContext())) {
Expand Down
88 changes: 2 additions & 86 deletions test/Concurrency/actor_defer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

func doSomething() {}

// expected-note @+1 6 {{calls to global function 'requiresMainActor()' from outside of its actor context are implicitly asynchronous}}
// expected-note @+1 4 {{calls to global function 'requiresMainActor()' from outside of its actor context are implicitly asynchronous}}
@MainActor func requiresMainActor() {}

@MainActor func testNonDefer_positive() {
Expand Down Expand Up @@ -66,7 +66,7 @@ func testGlobalActorAsync_negative() async {

@available(SwiftStdlib 5.1, *)
actor Actor {
// expected-note @+1 6 {{mutation of this property is only permitted within the actor}}
// expected-note @+1 3 {{mutation of this property is only permitted within the actor}}
var actorProperty = 0

func testActor_positive() {
Expand All @@ -76,13 +76,6 @@ actor Actor {
doSomething()
}

func testActor_task_positive() {
Task {
defer { actorProperty += 1 }
doSomething()
}
}

#if NEGATIVES
nonisolated func testActor_negative() {
defer {
Expand All @@ -91,30 +84,13 @@ actor Actor {
}
doSomething()
}

nonisolated func testActor_task_negative() {
Task {
// expected-error @+1 {{actor-isolated property 'actorProperty' can not be mutated from a non-isolated context}}
defer { actorProperty += 1 }
doSomething()
}
}

@MainActor func testActor_negative_globalActor() {
defer {
// expected-error @+1 {{actor-isolated property 'actorProperty' can not be mutated from the main actor}}
actorProperty += 1
}
doSomething()
}

func testActor_task_negative_globalActor() {
Task { @MainActor in
// expected-error @+1 {{actor-isolated property 'actorProperty' can not be mutated from the main actor}}
defer { actorProperty += 1 }
doSomething()
}
}
#endif

@MainActor func testGlobalActor_positive() {
Expand All @@ -123,13 +99,6 @@ actor Actor {
}
doSomething()
}

func testGlobalActor_task_positive() {
Task { @MainActor in
defer { requiresMainActor() }
doSomething()
}
}

#if NEGATIVES
func testGlobalActor_negative() {
Expand All @@ -139,14 +108,6 @@ actor Actor {
}
doSomething()
}

func testGlobalActor_task_negative() {
Task {
// expected-error @+1 {{call to main actor-isolated global function 'requiresMainActor()' in a synchronous nonisolated context}}
defer { requiresMainActor() }
doSomething()
}
}
#endif
}

Expand All @@ -169,48 +130,3 @@ func testIsolatedActor_negative(actor: Actor) {
doSomething()
}
#endif

@available(SwiftStdlib 5.1, *)
func testGlobalActor_inTask_positive() {
Task { @MainActor in
defer { requiresMainActor() }
doSomething()
}
}

#if NEGATIVES
@available(SwiftStdlib 5.1, *)
func testGlobalActor_inTask_negative() {
Task {
// expected-error @+1 {{call to main actor-isolated global function 'requiresMainActor()' in a synchronous nonisolated context}}
defer { requiresMainActor() }
doSomething()
}
}
#endif

@available(SwiftStdlib 5.1, *)
func takeClosureWithIsolatedParam(body: (isolated Actor) -> Void) {}

@available(SwiftStdlib 5.1, *)
func takeClosureWithNotIsolatedParam(body: (Actor) -> Void) {}

@available(SwiftStdlib 5.1, *)
func testIsolatedActor_closure_positive() {
takeClosureWithIsolatedParam { actor in
actor.actorProperty += 1
defer { actor.actorProperty += 1 }
doSomething()
}
}

#if NEGATIVES
@available(SwiftStdlib 5.1, *)
func testIsolatedActor_closure_negative() {
takeClosureWithNotIsolatedParam { actor in
// expected-error @+1 {{actor-isolated property 'actorProperty' can not be mutated from a non-isolated context}}
defer { actor.actorProperty += 1 }
doSomething()
}
}
#endif