Skip to content

Commit d2c3e46

Browse files
committed
Make toplevel vars MainActor with warn-concurrency
This is the last part to implement SE-0343. When `-warn-concurrency` is passed to the compiler invocation, we want to protect top-level variables behind the MainActor regardless of whether the top-level is an asynchronous context. Note that this does not make the top-level an asynchronous context, but it does annotate the top-level as being a main-actor-protected context.
1 parent e3b2719 commit d2c3e46

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9056,7 +9056,9 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
90569056
}
90579057

90589058
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
9059-
if (dc->isAsyncContext()) {
9059+
if (dc->isAsyncContext() ||
9060+
(dc->getASTContext().LangOpts.WarnConcurrency &&
9061+
dc->getASTContext().LangOpts.EnableExperimentalAsyncTopLevel)) {
90609062
if (Type mainActor = dc->getASTContext().getMainActorType())
90619063
return ActorIsolation::forGlobalActor(mainActor, /*unsafe=*/false);
90629064
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ GlobalActorAttributeRequest::evaluate(
344344
if (auto var = dyn_cast<VarDecl>(storage)) {
345345

346346
// ... but not if it's an async-context top-level global
347-
if (var->isTopLevelGlobal() && var->getDeclContext()->isAsyncContext()) {
347+
if (var->getASTContext().LangOpts.EnableExperimentalAsyncTopLevel &&
348+
var->isTopLevelGlobal() && (var->getDeclContext()->isAsyncContext()
349+
|| var->getASTContext().LangOpts.WarnConcurrency)) {
348350
var->diagnose(diag::global_actor_top_level_var)
349351
.highlight(globalActorAttr->getRangeWithAt());
350352
return None;
@@ -3818,7 +3820,10 @@ ActorIsolation ActorIsolationRequest::evaluate(
38183820
}
38193821

38203822
if (auto var = dyn_cast<VarDecl>(value)) {
3821-
if (var->isTopLevelGlobal() && var->getDeclContext()->isAsyncContext()) {
3823+
if (var->getASTContext().LangOpts.EnableExperimentalAsyncTopLevel &&
3824+
var->isTopLevelGlobal() &&
3825+
(var->getASTContext().LangOpts.WarnConcurrency ||
3826+
var->getDeclContext()->isAsyncContext())) {
38223827
if (Type mainActor = var->getASTContext().getMainActorType())
38233828
return inferredIsolation(
38243829
ActorIsolation::forGlobalActor(mainActor,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-frontend -disable-availability-checking -enable-experimental-async-top-level -warn-concurrency -typecheck -verify %s
2+
3+
var a = 10 // expected-note{{var declared here}}
4+
5+
@MainActor
6+
var b = 15 // expected-error{{top-level code variables cannot have a global actor}}
7+
8+
func unsafeAccess() { // expected-note{{add '@MainActor' to make global function 'unsafeAccess()' part of global actor 'MainActor'}}
9+
print(a) // expected-error@:11{{var 'a' isolated to global actor 'MainActor' can not be referenced from this synchronous context}}
10+
}
11+
12+
func unsafeAsyncAccess() async {
13+
print(a) // expected-error@:5{{expression is 'async' but is not marked with 'await'}}{{5-5=await }}
14+
// expected-note@-1:11{{property access is 'async'}}
15+
}
16+
17+
@MainActor
18+
func safeAccess() {
19+
print(a)
20+
}
21+
22+
@MainActor
23+
func safeSyncAccess() async {
24+
print(a)
25+
}
26+
27+
func safeAsyncAccess() async {
28+
await print(a)
29+
}
30+
31+
print(a)

0 commit comments

Comments
 (0)