Skip to content

Commit 4cd5f6a

Browse files
authored
Merge pull request #73572 from DougGregor/infer-isolation-from-inherited-protocols
Infer protocol isolation from its inherited protocols.
2 parents a8a0dd8 + 90341b2 commit 4cd5f6a

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

lib/Sema/TypeCheckConcurrency.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -4545,6 +4545,37 @@ getIsolationFromConformances(NominalTypeDecl *nominal) {
45454545
return foundIsolation;
45464546
}
45474547

4548+
/// Compute the isolation of a protocol
4549+
static std::optional<ActorIsolation>
4550+
getIsolationFromInheritedProtocols(ProtocolDecl *protocol) {
4551+
std::optional<ActorIsolation> foundIsolation;
4552+
for (auto inherited : protocol->getInheritedProtocols()) {
4553+
switch (auto protoIsolation = getActorIsolation(inherited)) {
4554+
case ActorIsolation::ActorInstance:
4555+
case ActorIsolation::Unspecified:
4556+
case ActorIsolation::Nonisolated:
4557+
case ActorIsolation::NonisolatedUnsafe:
4558+
break;
4559+
4560+
case ActorIsolation::Erased:
4561+
llvm_unreachable("protocol cannot have erased isolation");
4562+
4563+
case ActorIsolation::GlobalActor:
4564+
if (!foundIsolation) {
4565+
foundIsolation = protoIsolation;
4566+
continue;
4567+
}
4568+
4569+
if (*foundIsolation != protoIsolation)
4570+
return std::nullopt;
4571+
4572+
break;
4573+
}
4574+
}
4575+
4576+
return foundIsolation;
4577+
}
4578+
45484579
/// Compute the isolation of a nominal type from the property wrappers on
45494580
/// any stored properties.
45504581
static std::optional<ActorIsolation>
@@ -5236,6 +5267,17 @@ ActorIsolation ActorIsolationRequest::evaluate(
52365267
if (auto inferred = inferredIsolation(*conformanceIsolation))
52375268
return inferred;
52385269

5270+
// For a protocol, inherit isolation from the directly-inherited
5271+
// protocols.
5272+
if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability)) {
5273+
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
5274+
if (auto protoIsolation = getIsolationFromInheritedProtocols(proto)) {
5275+
if (auto inferred = inferredIsolation(*protoIsolation))
5276+
return inferred;
5277+
}
5278+
}
5279+
}
5280+
52395281
// Before Swift 6: If the declaration is a nominal type and any property
52405282
// wrappers on its stored properties require isolation, use that.
52415283
if (auto wrapperIsolation = getIsolationFromWrappers(nominal)) {

test/Concurrency/global_actor_inference_swift6.swift

+26
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,29 @@ class C {
153153
struct S: InferMainActor {
154154
@Wrapper var value: C // okay, 'S' is isolated to 'MainActor'
155155
}
156+
157+
protocol InferMainActorInherited: InferMainActor {
158+
func f() // expected-note{{mark the protocol requirement 'f()' 'async' to allow actor-isolated conformances}}
159+
func g()
160+
}
161+
162+
@SomeGlobalActor
163+
protocol InferSomeGlobalActor { }
164+
165+
protocol InferenceConflict: InferMainActorInherited, InferSomeGlobalActor { }
166+
167+
struct S2: InferMainActorInherited {
168+
func f() { } // okay, 'f' is MainActor isolated, as is the requirement
169+
@MainActor func g() { } // okay for the same reasons, but more explicitly
170+
}
171+
172+
@SomeGlobalActor
173+
struct S3: InferenceConflict {
174+
nonisolated func g() { }
175+
}
176+
177+
extension S3 {
178+
func f() { }
179+
// expected-error@-1{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot be used to satisfy main actor-isolated protocol requirement}}
180+
//expected-note@-2{{add 'nonisolated' to 'f()' to make this instance method not isolated to the actor}}
181+
}

0 commit comments

Comments
 (0)