Skip to content

Commit 858e145

Browse files
committed
[Concurrency] Only apply default main actor to local and nested
decls that are in a main actor isolated context. This prevents `@MainActor` from being inferred in a context where it cannot be used, while still allowing main actor code to be used in local contexts that are also main actor isolated.
1 parent 4b50238 commit 858e145

File tree

2 files changed

+62
-14
lines changed

2 files changed

+62
-14
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6083,28 +6083,33 @@ computeDefaultInferredActorIsolation(ValueDecl *value) {
60836083
auto globalActorHelper = [&](Type globalActor)
60846084
-> std::optional<std::tuple<InferredActorIsolation, ValueDecl *,
60856085
std::optional<ActorIsolation>>> {
6086-
// Default global actor isolation does not apply to any declarations
6087-
// within actors and distributed actors, nor does it apply in a
6088-
// nonisolated type.
6086+
// Default main actor only applies to top-level declarations and
6087+
// in contexts that are also main actor isolated. It does not apply
6088+
// in {distributed} actor-isolated contexts nor in nonisolated
6089+
// contexts.
6090+
6091+
// Local declarations must check the isolation of their
6092+
// decl context.
6093+
if (value->getDeclContext()->isLocalContext()) {
6094+
auto contextIsolation =
6095+
getActorIsolationOfContext(value->getDeclContext());
6096+
if (!contextIsolation.isMainActor())
6097+
return {};
6098+
}
6099+
6100+
// Members and nested types must check the isolation of the enclosing
6101+
// nominal type.
60896102
auto *dc = value->getInnermostDeclContext();
60906103
while (dc) {
60916104
if (auto *nominal = dc->getSelfNominalTypeDecl()) {
60926105
if (nominal->isAnyActor())
60936106
return {};
60946107

60956108
if (dc != dyn_cast<DeclContext>(value)) {
6096-
switch (getActorIsolation(nominal)) {
6097-
case ActorIsolation::Unspecified:
6098-
case ActorIsolation::ActorInstance:
6099-
case ActorIsolation::Nonisolated:
6100-
case ActorIsolation::NonisolatedUnsafe:
6101-
case ActorIsolation::Erased:
6102-
case ActorIsolation::CallerIsolationInheriting:
6103-
return {};
6104-
6105-
case ActorIsolation::GlobalActor:
6109+
if (getActorIsolation(nominal).isMainActor())
61066110
break;
6107-
}
6111+
6112+
return {};
61086113
}
61096114
}
61106115
dc = dc->getParent();

test/Concurrency/assume_mainactor.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,46 @@ struct S: P {
244244
}
245245
static let at = AT() // used to fail here
246246
}
247+
248+
nonisolated func localDeclIsolation() async {
249+
struct Local {
250+
static func f() {}
251+
}
252+
253+
Local.f()
254+
255+
await withTaskGroup { group in
256+
group.addTask { }
257+
258+
await group.next()
259+
}
260+
}
261+
262+
@CustomActor
263+
class CustomActorIsolated {
264+
struct Nested {
265+
// CHECK: // static CustomActorIsolated.Nested.f()
266+
// CHECK-NEXT: // Isolation: unspecified
267+
static func f() {}
268+
}
269+
270+
// CHECK: // CustomActorIsolated.customIsolated()
271+
// CHECK-NEXT: // Isolation: global_actor. type: CustomActor
272+
func customIsolated() {
273+
Nested.f()
274+
}
275+
}
276+
277+
var global = 0
278+
279+
func onMain() {
280+
struct Nested {
281+
// CHECK: // static useGlobal() in Nested #1 in onMain()
282+
// CHECK-NEXT: // Isolation: global_actor. type: MainActor
283+
static func useGlobal() -> Int {
284+
global
285+
}
286+
}
287+
288+
_ = Nested.useGlobal()
289+
}

0 commit comments

Comments
 (0)