Skip to content

Commit 51cdcc6

Browse files
authored
Merge pull request #73579 from DougGregor/infer-isolation-from-inherited-protocols-6.0
2 parents f593cd1 + 337a99d commit 51cdcc6

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4543,6 +4543,37 @@ getIsolationFromConformances(NominalTypeDecl *nominal) {
45434543
return foundIsolation;
45444544
}
45454545

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

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

test/Concurrency/global_actor_inference_swift6.swift

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

0 commit comments

Comments
 (0)