Skip to content

Commit 5342706

Browse files
committed
[Actor inference] Infer global actors on a type based on conformances.
If a protocol is stated to be part of a global actor, infer that a type that conforms to a protocol in its original definition is also part of that global actor. Addresses rdar://75992299.
1 parent 360fe60 commit 5342706

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,6 +2498,38 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
24982498
return std::get<1>(isolatedRequirements.front());
24992499
}
25002500

2501+
/// Compute the isolation of a nominal type from the conformances that
2502+
/// are directly specified on the type.
2503+
static Optional<ActorIsolation> getIsolationFromConformances(
2504+
NominalTypeDecl *nominal) {
2505+
if (isa<ProtocolDecl>(nominal))
2506+
return None;
2507+
2508+
Optional<ActorIsolation> foundIsolation;
2509+
for (auto proto : nominal->getLocalProtocols()) {
2510+
switch (auto protoIsolation = getActorIsolation(proto)) {
2511+
case ActorIsolation::ActorInstance:
2512+
case ActorIsolation::Unspecified:
2513+
case ActorIsolation::Independent:
2514+
break;
2515+
2516+
case ActorIsolation::GlobalActor:
2517+
case ActorIsolation::GlobalActorUnsafe:
2518+
if (!foundIsolation) {
2519+
foundIsolation = protoIsolation;
2520+
continue;
2521+
}
2522+
2523+
if (*foundIsolation != protoIsolation)
2524+
return None;
2525+
2526+
break;
2527+
}
2528+
}
2529+
2530+
return foundIsolation;
2531+
}
2532+
25012533
// Check whether a declaration is an asynchronous handler.
25022534
static bool isAsyncHandler(ValueDecl *value) {
25032535
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
@@ -2721,6 +2753,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
27212753
}
27222754
}
27232755
}
2756+
2757+
// If the declaration is a nominal type and any of the protocols to which
2758+
// it directly conforms is isolated to a global actor, use that.
2759+
if (auto nominal = dyn_cast<NominalTypeDecl>(value)) {
2760+
if (auto conformanceIsolation = getIsolationFromConformances(nominal))
2761+
if (auto inferred = inferredIsolation(*conformanceIsolation))
2762+
return inferred;
2763+
}
27242764
}
27252765

27262766
// Infer isolation for a member.

test/Concurrency/global_actor_inference.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,30 @@ class C2: P2 {
6868
}
6969
}
7070

71+
struct AllInP1: P1 {
72+
func method() { } // expected-note {{calls to instance method 'method()' from outside of its actor context are implicitly asynchronous}}
73+
func other() { } // expected-note {{calls to instance method 'other()' from outside of its actor context are implicitly asynchronous}}
74+
}
75+
76+
func testAllInP1(ap1: AllInP1) { // expected-note 2 {{add '@SomeGlobalActor' to make global function 'testAllInP1(ap1:)' part of global actor 'SomeGlobalActor'}}
77+
ap1.method() // expected-error{{instance method 'method()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
78+
ap1.other() // expected-error{{instance method 'other()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
79+
}
80+
81+
struct NotAllInP1 {
82+
func other() { }
83+
}
84+
85+
extension NotAllInP1: P1 {
86+
func method() { } // expected-note{{calls to instance method 'method()' from outside of its actor context are implicitly asynchronous}}
87+
}
88+
89+
func testNotAllInP1(nap1: NotAllInP1) { // expected-note{{add '@SomeGlobalActor' to make global function 'testNotAllInP1(nap1:)' part of global actor 'SomeGlobalActor'}}
90+
nap1.method() // expected-error{{instance method 'method()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
91+
nap1.other() // okay
92+
}
93+
94+
7195
// ----------------------------------------------------------------------
7296
// Global actor inference for classes and extensions
7397
// ----------------------------------------------------------------------

0 commit comments

Comments
 (0)