Skip to content

Commit d265ec9

Browse files
authored
Merge pull request #40998 from etcwilde/ewilde/mainactor-top-level-vars
Make top-level code variables `@MainActor @preconcurrency`
2 parents b7ecf2a + 8d509ad commit d265ec9

File tree

7 files changed

+155
-62
lines changed

7 files changed

+155
-62
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4771,7 +4771,9 @@ ERROR(global_actor_non_unsafe_init,none,
47714771
"global actor attribute %0 argument can only be '(unsafe)'", (Type))
47724772
ERROR(global_actor_non_final_class,none,
47734773
"non-final class %0 cannot be a global actor", (DeclName))
4774-
4774+
ERROR(global_actor_top_level_var,none,
4775+
"top-level code variables cannot have a global actor", ())
4776+
47754777
ERROR(actor_isolation_multiple_attr,none,
47764778
"%0 %1 has multiple actor-isolation attributes ('%2' and '%3')",
47774779
(DescriptiveDeclKind, DeclName, StringRef, StringRef))

lib/AST/Decl.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,16 @@ bool Decl::preconcurrency() const {
733733
if (isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext()))
734734
return true;
735735

736+
// Variables declared in top-level code are @_predatesConcurrency
737+
if (const VarDecl *var = dyn_cast<VarDecl>(this)) {
738+
const LangOptions &langOpts = getASTContext().LangOpts;
739+
return !langOpts.isSwiftVersionAtLeast(6) &&
740+
langOpts.EnableExperimentalAsyncTopLevel && var->isTopLevelGlobal();
741+
}
742+
736743
return false;
737744
}
738745

739-
740746
Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
741747
assert(hasSingleExpressionBody() && "Not a single-expression body");
742748
auto braceStmt = getBody();
@@ -8939,6 +8945,14 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
89398945
}
89408946
}
89418947

8948+
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
8949+
ASTContext &ctx = dc->getASTContext();
8950+
if (ctx.LangOpts.EnableExperimentalAsyncTopLevel) {
8951+
if (Type mainActor = ctx.getMainActorType())
8952+
return ActorIsolation::forGlobalActor(mainActor, /*unsafe=*/false);
8953+
}
8954+
}
8955+
89428956
return ActorIsolation::forUnspecified();
89438957
}
89448958

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,12 @@ GlobalActorAttributeRequest::evaluate(
271271
} else if (auto storage = dyn_cast<AbstractStorageDecl>(decl)) {
272272
// Subscripts and properties are fine...
273273
if (auto var = dyn_cast<VarDecl>(storage)) {
274-
if (var->getDeclContext()->isLocalContext() && !var->isTopLevelGlobal()) {
274+
if (var->isTopLevelGlobal() &&
275+
var->getASTContext().LangOpts.EnableExperimentalAsyncTopLevel) {
276+
var->diagnose(diag::global_actor_top_level_var)
277+
.highlight(globalActorAttr->getRangeWithAt());
278+
return None;
279+
} else if (var->getDeclContext()->isLocalContext()) {
275280
var->diagnose(diag::global_actor_on_local_variable, var->getName())
276281
.highlight(globalActorAttr->getRangeWithAt());
277282
return None;
@@ -3505,6 +3510,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
35053510
}
35063511

35073512
if (auto var = dyn_cast<VarDecl>(value)) {
3513+
ASTContext &ctx = var->getASTContext();
3514+
if (var->isTopLevelGlobal() &&
3515+
ctx.LangOpts.EnableExperimentalAsyncTopLevel) {
3516+
if (Type mainActor = ctx.getMainActorType())
3517+
return inferredIsolation(
3518+
ActorIsolation::forGlobalActor(mainActor,
3519+
/*unsafe=*/var->preconcurrency()));
3520+
}
35083521
if (auto isolation = getActorIsolationFromWrappedProperty(var))
35093522
return inferredIsolation(isolation);
35103523
}

lib/Sema/TypeCheckConcurrency.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class ActorIsolationRestriction {
199199
}
200200

201201
/// Determine the isolation rules for a given declaration.
202+
/// The isolation restriction represents the isolation requirement of the
203+
/// using context.
202204
///
203205
/// \param fromExpression Indicates that the reference is coming from an
204206
/// expression.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func foo() -> Int {
2+
a + 10
3+
}

test/Concurrency/toplevel/main.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: not %target-swift-frontend -enable-experimental-async-top-level -swift-version 6 -typecheck %s %S/Inputs/foo.swift 2>&1 | %FileCheck %s --check-prefixes='Swift6-CHECK,CHECK'
2+
// RUN: not %target-swift-frontend -enable-experimental-async-top-level -swift-version 5 -typecheck %s %S/Inputs/foo.swift 2>&1 | %FileCheck %s --check-prefixes='Swift5-CHECK,CHECK'
3+
4+
var a = 10
5+
6+
@MainActor
7+
var b = 14
8+
// CHECK: top-level code variables cannot have a global actor
9+
10+
func nonIsolatedSynchronous() {
11+
print(a)
12+
// Swift6-CHECK: var 'a' isolated to global actor 'MainActor'
13+
// Swift6-CHECK: add '@MainActor' to make global function 'nonIsolatedSynchronous()' part of global actor 'MainActor'
14+
15+
// Swift5-CHECK-NOT: var 'a' isolated to global actor 'MainActor'
16+
// Swift5-CHECK-NOT: add '@MainActor' to make global function 'nonIsolatedSynchronous()' part of global actor 'MainActor'
17+
}
18+
19+
func nonIsolatedAsync() async {
20+
print(a)
21+
// CHECK: expression is 'async' but is not marked with 'await'
22+
// CHECK: property access is 'async'
23+
}
24+
25+
await nonIsolatedAsync()
26+
27+
// Swift6-CHECK: foo.swift{{.*}}var 'a' isolated to global actor 'MainActor' can not be referenced from this synchronous context
28+
// Swift6-CHECK: foo.swift{{.*}}add '@MainActor' to make global function 'foo()' part of global actor 'MainActor'
29+
// Swift6-CHECK: var declared here
30+
31+
// Swift5-CHECK-NOT: foo.swift{{.*}}var 'a' isolated to global actor 'MainActor' can not be referenced from this synchronous context
32+
// Swift5-CHECK-NOT: foo.swift{{.*}}add '@MainActor' to make global function 'foo()' part of global actor 'MainActor'
33+
// Swift5-CHECK-NOT: var declared here
34+
35+
@MainActor
36+
func isolated() {
37+
print(a)
38+
}
39+
40+
func asyncFun() async {
41+
await print(a)
42+
}
43+
44+
await asyncFun()
Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,126 @@
1-
// RUN: %target-swift-emit-silgen -Xllvm -sil-full-demangle -enable-experimental-async-top-level %s | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen -Xllvm -sil-full-demangle -disable-availability-checking -enable-experimental-async-top-level %s | %FileCheck %s
22

33
// a
44
// CHECK-LABEL: sil_global hidden @$s24toplevel_globalactorvars1aSivp : $Int
5-
// b
6-
// CHECK-LABEL: sil_global hidden @$s24toplevel_globalactorvars1bSivp : $Int
75

86
// CHECK-LABEL: sil hidden [ossa] @async_Main
97
// CHECK: bb0:
108
// CHECK-NEXT: // function_ref
119
// CHECK-NEXT: [[GET_MAIN:%.*]] = function_ref @swift_task_getMainExecutor
1210
// CHECK-NEXT: [[MAIN:%.*]] = apply [[GET_MAIN]]()
13-
// CHECK-NEXT: alloc_global @$s24toplevel_globalactorvars1aSivp
14-
// CHECK-NEXT: [[AREF:%[0-9]+]] = global_addr @$s24toplevel_globalactorvars1aSivp : $*Int
1511

16-
@available(SwiftStdlib 5.1, *)
1712
actor MyActorImpl {}
1813

19-
@available(SwiftStdlib 5.1, *)
2014
@globalActor
2115
struct MyActor {
2216
static let shared = MyActorImpl()
2317
}
2418

25-
@MyActor
2619
var a = 10
2720

21+
// a initialization
22+
// CHECK: alloc_global @$s24toplevel_globalactorvars1aSivp
23+
// CHECK: [[AREF:%[0-9]+]] = global_addr @$s24toplevel_globalactorvars1aSivp
24+
// CHECK: [[TEN_LIT:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 10
25+
// CHECK: [[INT_TYPE:%[0-9]+]] = metatype $@thin Int.Type
26+
// CHECK: [[INT_INIT:%[0-9]+]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC
27+
// CHECK: [[TEN:%[0-9]+]] = apply [[INT_INIT]]([[TEN_LIT]], [[INT_TYPE]])
28+
// CHECK: store [[TEN]] to [trivial] [[AREF]]
29+
2830
@MyActor
29-
func incrementA() {
30-
a += 1
31+
func printFromMyActor(value : Int) {
32+
print(value)
3133
}
3234

33-
await print(a)
35+
print(a)
36+
37+
// print
38+
// CHECK-NOT: hop_to_executor
3439

35-
// CHECK: [[ACTORREF:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MyActorImpl
36-
// CHECK: hop_to_executor [[ACTORREF]] : $MyActorImpl
3740
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [read] [dynamic] [[AREF]] : $*Int
3841
// CHECK: [[AGLOBAL:%[0-9]+]] = load [trivial] [[AACCESS]] : $*Int
3942
// CHECK: end_access [[AACCESS]]
40-
// CHECK: hop_to_executor [[MAIN]]
41-
// CHECK: end_borrow [[ACTORREF]]
43+
// CHECK-NOT: hop_to_executor
44+
45+
a += 1
46+
47+
// CHECK: [[ONE_LIT:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 1
48+
// CHECK: [[INT_TYPE:%[0-9]+]] = metatype $@thin Int.Type
49+
// CHECK: [[INT_INIT:%[0-9]+]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC
50+
// CHECK: [[ONE:%[0-9]+]] = apply [[INT_INIT]]([[ONE_LIT]], [[INT_TYPE]])
51+
// CHECK-NOT: hop_to_executor
52+
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [modify] [dynamic] [[AREF]] : $*Int
53+
// static Int.+= infix(_:_:)
54+
// CHECK: [[PE_INT_FUNC:%[0-9]+]] = function_ref @$sSi2peoiyySiz_SitFZ
55+
// CHECK: [[INCREMENTED:%[0-9]+]] = apply [[PE_INT_FUNC]]([[AACCESS]], [[ONE]], {{%[0-9]+}})
56+
// CHECK: end_access [[AACCESS]]
57+
// CHECK-NOT: hop_to_executor
58+
4259

43-
await incrementA()
60+
await printFromMyActor(value: a)
61+
62+
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [read] [dynamic] [[AREF]] : $*Int
63+
// CHECK: [[AGLOBAL:%[0-9]+]] = load [trivial] [[AACCESS]] : $*Int
64+
// CHECK: end_access [[AACCESS]]
4465

45-
// CHECK: [[INCREMENTA:%[0-9]+]] = function_ref @$s24toplevel_globalactorvars10incrementAyyF
66+
// CHECK: [[PRINTFROMMYACTOR_FUNC:%[0-9]+]] = function_ref @$s24toplevel_globalactorvars16printFromMyActor5valueySi_tF
4667
// CHECK: [[ACTORREF:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MyActorImpl
4768
// CHECK: hop_to_executor [[ACTORREF]] : $MyActorImpl
48-
// CHECK: {{%[0-9]+}} = apply [[INCREMENTA]]()
69+
// CHECK: {{%[0-9]+}} = apply [[PRINTFROMMYACTOR_FUNC]]([[AGLOBAL]])
4970
// CHECK: hop_to_executor [[MAIN]]
5071
// CHECK: end_borrow [[ACTORREF]]
5172

52-
await print(a)
53-
54-
// CHECK: [[ACTORREF:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MyActorImpl
55-
// CHECK: hop_to_executor [[ACTORREF]] : $MyActorImpl
73+
if a < 10 {
5674
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [read] [dynamic] [[AREF]] : $*Int
5775
// CHECK: [[AGLOBAL:%[0-9]+]] = load [trivial] [[AACCESS]] : $*Int
5876
// CHECK: end_access [[AACCESS]]
59-
// CHECK: hop_to_executor [[MAIN]]
60-
// CHECK: end_borrow [[ACTORREF]]
6177

62-
var b = 11
78+
// CHECK: [[TEN_LIT:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 10
79+
// CHECK: [[INT_TYPE:%[0-9]+]] = metatype $@thin Int.Type
80+
// CHECK: [[INT_INIT:%[0-9]+]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC
81+
// CHECK: [[TEN:%[0-9]+]] = apply [[INT_INIT]]([[TEN_LIT]], [[INT_TYPE]])
82+
// function_ref static Swift.Int.< infix(Swift.Int, Swift.Int) -> Swift.Bool
83+
// CHECK: [[LESS_FUNC:%[0-9]+]] = function_ref @$sSi1loiySbSi_SitFZ
84+
// CHECK: [[WRAPPED_COND:%[0-9]+]] = apply [[LESS_FUNC]]([[AGLOBAL]], [[TEN]], {{%[0-9]+}})
85+
// CHECK: [[COND:%[0-9]+]] = struct_extract [[WRAPPED_COND]]
86+
// CHECK: cond_br [[COND]], bb1, bb2
87+
// CHECK: bb1:
88+
89+
print(a)
6390

64-
// CHECK: alloc_global @$s24toplevel_globalactorvars1bSivp
65-
// CHECK: [[BGLOBAL_ADDR:%[0-9]+]] = global_addr @$s24toplevel_globalactorvars1bSivp
66-
// Int.init(_builtinIntegerLiteral:)
67-
// CHECK: [[INT_INIT_FUNC:%[0-9]+]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC
68-
// CHECK: [[INITD_INT:%[0-9]+]] = apply [[INT_INIT_FUNC]]({{%[0-9]+}}, {{%[0-9]+}})
69-
// CHECK: store [[INITD_INT]] to [trivial] [[BGLOBAL_ADDR]]
91+
// print
92+
// CHECK-NOT: hop_to_executor
7093

71-
b += 1
94+
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [read] [dynamic] [[AREF]] : $*Int
95+
// CHECK: [[AGLOBAL:%[0-9]+]] = load [trivial] [[AACCESS]] : $*Int
96+
// CHECK: end_access [[AACCESS]]
97+
// CHECK-NOT: hop_to_executor
7298

73-
// CHECK-NOT: hop_to_executor
74-
// CHECK: [[BACCESS:%[0-9]+]] = begin_access [modify] [dynamic] [[BGLOBAL_ADDR]]
75-
// static Int.+= infix(_:_:)
76-
// CHECK: [[PE_INT_FUNC:%[0-9]+]] = function_ref @$sSi2peoiyySiz_SitFZ
77-
// CHECK: [[INCREMENTED:%[0-9]+]] = apply [[PE_INT_FUNC]]([[BACCESS]], {{%[0-9]+}}, {{%[0-9]+}})
78-
// CHECK: end_access [[BACCESS]]
99+
a += 1
100+
101+
// CHECK: [[ONE_LIT:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 1
102+
// CHECK: [[INT_TYPE:%[0-9]+]] = metatype $@thin Int.Type
103+
// CHECK: [[INT_INIT:%[0-9]+]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC
104+
// CHECK: [[ONE:%[0-9]+]] = apply [[INT_INIT]]([[ONE_LIT]], [[INT_TYPE]])
105+
// CHECK-NOT: hop_to_executor
106+
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [modify] [dynamic] [[AREF]] : $*Int
107+
// static Int.+= infix(_:_:)
108+
// CHECK: [[PE_INT_FUNC:%[0-9]+]] = function_ref @$sSi2peoiyySiz_SitFZ
109+
// CHECK: [[INCREMENTED:%[0-9]+]] = apply [[PE_INT_FUNC]]([[AACCESS]], [[ONE]], {{%[0-9]+}})
110+
// CHECK: end_access [[AACCESS]]
111+
// CHECK-NOT: hop_to_executor
79112

80113

81-
// CHECK: bb1:
82-
if #available(SwiftStdlib 5.1, *) {
83-
await print(a)
114+
await printFromMyActor(value: a)
84115

85-
// CHECK: [[ACTORREF:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MyActorImpl
86-
// CHECK: hop_to_executor [[ACTORREF]] : $MyActorImpl
87116
// CHECK: [[AACCESS:%[0-9]+]] = begin_access [read] [dynamic] [[AREF]] : $*Int
88117
// CHECK: [[AGLOBAL:%[0-9]+]] = load [trivial] [[AACCESS]] : $*Int
89118
// CHECK: end_access [[AACCESS]]
90-
// CHECK: hop_to_executor [[MAIN]]
91-
// CHECK: end_borrow [[ACTORREF]]
92119

93-
await incrementA()
94-
95-
// CHECK: [[INCREMENTA:%[0-9]+]] = function_ref @$s24toplevel_globalactorvars10incrementAyyF
120+
// CHECK: [[PRINTFROMMYACTOR_FUNC:%[0-9]+]] = function_ref @$s24toplevel_globalactorvars16printFromMyActor5valueySi_tF
96121
// CHECK: [[ACTORREF:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MyActorImpl
97122
// CHECK: hop_to_executor [[ACTORREF]] : $MyActorImpl
98-
// CHECK: {{%[0-9]+}} = apply [[INCREMENTA]]()
123+
// CHECK: {{%[0-9]+}} = apply [[PRINTFROMMYACTOR_FUNC]]([[AGLOBAL]])
99124
// CHECK: hop_to_executor [[MAIN]]
100125
// CHECK: end_borrow [[ACTORREF]]
101-
102-
103-
b += 1
104-
105-
// CHECK-NOT: hop_to_executor
106-
// CHECK: [[BACCESS:%[0-9]+]] = begin_access [modify] [dynamic] [[BGLOBAL_ADDR]]
107-
// static Int.+= infix(_:_:)
108-
// CHECK: [[PE_INT_FUNC:%[0-9]+]] = function_ref @$sSi2peoiyySiz_SitFZ
109-
// CHECK: [[INCREMENTED:%[0-9]+]] = apply [[PE_INT_FUNC]]([[BACCESS]], {{%[0-9]+}}, {{%[0-9]+}})
110-
// CHECK: end_access [[BACCESS]]
111126
}

0 commit comments

Comments
 (0)