Skip to content

Commit 0f8e1ca

Browse files
committed
Clean up and test global actor propagation rules
1 parent 5eea13e commit 0f8e1ca

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,12 +2813,15 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
28132813
overridden->diagnose(diag::overridden_here);
28142814
}
28152815

2816-
static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
2817-
if (dc->getASTContext().LangOpts.WarnConcurrency)
2818-
return true;
2819-
2816+
bool swift::contextUsesConcurrencyFeatures(const DeclContext *dc) {
28202817
while (!dc->isModuleScopeContext()) {
28212818
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2819+
// A closure with an explicit global actor uses concurrency features.
2820+
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
2821+
if (getExplicitGlobalActor(const_cast<ClosureExpr *>(explicitClosure)))
2822+
return true;
2823+
}
2824+
28222825
// Async and concurrent closures use concurrency features.
28232826
if (auto closureType = closure->getType()) {
28242827
if (auto fnType = closureType->getAs<AnyFunctionType>())
@@ -2851,8 +2854,8 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
28512854
}
28522855

28532856
// If we're in an actor, we're using concurrency features.
2854-
if (auto classDecl = dc->getSelfClassDecl()) {
2855-
if (classDecl->isActor())
2857+
if (auto nominal = dc->getSelfNominalTypeDecl()) {
2858+
if (nominal->isActor())
28562859
return true;
28572860
}
28582861

@@ -2863,6 +2866,13 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
28632866
return false;
28642867
}
28652868

2869+
static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
2870+
if (dc->getASTContext().LangOpts.WarnConcurrency)
2871+
return true;
2872+
2873+
return contextUsesConcurrencyFeatures(dc);
2874+
}
2875+
28662876
static DiagnosticBehavior toDiagnosticBehavior(const LangOptions &langOpts,
28672877
ConcurrentValueCheck check,
28682878
bool diagnoseImplicit = false) {

lib/Sema/TypeCheckConcurrency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ class ActorIsolationRestriction {
177177
/// overridden declaration.
178178
void checkOverrideActorIsolation(ValueDecl *value);
179179

180+
/// Determine whether the given context uses concurrency features, such
181+
/// as async functions or actors.
182+
bool contextUsesConcurrencyFeatures(const DeclContext *dc);
183+
180184
/// Diagnose the presence of any non-concurrent types when referencing a
181185
/// given declaration from a particular declaration context.
182186
///

test/Concurrency/global_actor_function_types.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ func testConversions(f: @escaping @SomeGlobalActor (Int) -> Void, g: @escaping (
2424
}
2525

2626
@SomeGlobalActor func onSomeGlobalActor() -> Int { 5 }
27+
@SomeGlobalActor(unsafe) func onSomeGlobalActorUnsafe() -> Int { 5 }
28+
29+
@OtherGlobalActor func onOtherGlobalActor() -> Int { 5 } // expected-note{{calls to global function 'onOtherGlobalActor()' from outside of its actor context are implicitly asynchronous}}
30+
@OtherGlobalActor(unsafe) func onOtherGlobalActorUnsafe() -> Int { 5 } // expected-note 2{{calls to global function 'onOtherGlobalActorUnsafe()' from outside of its actor context are implicitly asynchronous}}
2731

2832
func someSlowOperation() async -> Int { 5 }
2933

3034
func acceptOnSomeGlobalActor<T>(_: @SomeGlobalActor () -> T) { }
3135

32-
func testClosures() {
36+
func testClosures() async {
3337
// Global actors on synchronous closures become part of the type
3438
let cl1 = { @SomeGlobalActor in
3539
onSomeGlobalActor()
@@ -47,6 +51,7 @@ func testClosures() {
4751
onSomeGlobalActor()
4852
}
4953

54+
// Infer from context
5055
acceptOnSomeGlobalActor {
5156
onSomeGlobalActor()
5257
}
@@ -55,4 +60,36 @@ func testClosures() {
5560
let i = onSomeGlobalActor()
5661
return i
5762
}
63+
64+
acceptOnSomeGlobalActor { () -> Int in
65+
let i = onOtherGlobalActorUnsafe() // expected-error{{global function 'onOtherGlobalActorUnsafe()' isolated to global actor 'OtherGlobalActor' can not be referenced from different global actor 'SomeGlobalActor' in a synchronous context}}
66+
return i
67+
}
68+
}
69+
70+
func testClosuresOld() {
71+
acceptOnSomeGlobalActor { () -> Int in
72+
let i = onSomeGlobalActor()
73+
return i
74+
}
75+
76+
acceptOnSomeGlobalActor { () -> Int in
77+
let i = onSomeGlobalActorUnsafe()
78+
return i
79+
}
80+
81+
acceptOnSomeGlobalActor { () -> Int in
82+
let i = onOtherGlobalActor() // expected-error{{global function 'onOtherGlobalActor()' isolated to global actor 'OtherGlobalActor' can not be referenced from different global actor 'SomeGlobalActor' in a synchronous context}}
83+
return i
84+
}
85+
86+
acceptOnSomeGlobalActor { () -> Int in
87+
let i = onOtherGlobalActorUnsafe()
88+
return i
89+
}
90+
91+
acceptOnSomeGlobalActor { @SomeGlobalActor () -> Int in
92+
let i = onOtherGlobalActorUnsafe() // expected-error{{global function 'onOtherGlobalActorUnsafe()' isolated to global actor 'OtherGlobalActor' can not be referenced from different global actor 'SomeGlobalActor' in a synchronous context}}
93+
return i
94+
}
5895
}

0 commit comments

Comments
 (0)