diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 6ae5baa44dba0..32328bad0e170 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4545,6 +4545,37 @@ getIsolationFromConformances(NominalTypeDecl *nominal) { return foundIsolation; } +/// Compute the isolation of a protocol +static std::optional +getIsolationFromInheritedProtocols(ProtocolDecl *protocol) { + std::optional foundIsolation; + for (auto inherited : protocol->getInheritedProtocols()) { + switch (auto protoIsolation = getActorIsolation(inherited)) { + case ActorIsolation::ActorInstance: + case ActorIsolation::Unspecified: + case ActorIsolation::Nonisolated: + case ActorIsolation::NonisolatedUnsafe: + break; + + case ActorIsolation::Erased: + llvm_unreachable("protocol cannot have erased isolation"); + + case ActorIsolation::GlobalActor: + if (!foundIsolation) { + foundIsolation = protoIsolation; + continue; + } + + if (*foundIsolation != protoIsolation) + return std::nullopt; + + break; + } + } + + return foundIsolation; +} + /// Compute the isolation of a nominal type from the property wrappers on /// any stored properties. static std::optional @@ -5236,6 +5267,17 @@ ActorIsolation ActorIsolationRequest::evaluate( if (auto inferred = inferredIsolation(*conformanceIsolation)) return inferred; + // For a protocol, inherit isolation from the directly-inherited + // protocols. + if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability)) { + if (auto proto = dyn_cast(nominal)) { + if (auto protoIsolation = getIsolationFromInheritedProtocols(proto)) { + if (auto inferred = inferredIsolation(*protoIsolation)) + return inferred; + } + } + } + // Before Swift 6: If the declaration is a nominal type and any property // wrappers on its stored properties require isolation, use that. if (auto wrapperIsolation = getIsolationFromWrappers(nominal)) { diff --git a/test/Concurrency/global_actor_inference_swift6.swift b/test/Concurrency/global_actor_inference_swift6.swift index 893fceae8f246..1f933a7418a7c 100644 --- a/test/Concurrency/global_actor_inference_swift6.swift +++ b/test/Concurrency/global_actor_inference_swift6.swift @@ -153,3 +153,29 @@ class C { struct S: InferMainActor { @Wrapper var value: C // okay, 'S' is isolated to 'MainActor' } + +protocol InferMainActorInherited: InferMainActor { + func f() // expected-note{{mark the protocol requirement 'f()' 'async' to allow actor-isolated conformances}} + func g() +} + +@SomeGlobalActor +protocol InferSomeGlobalActor { } + +protocol InferenceConflict: InferMainActorInherited, InferSomeGlobalActor { } + +struct S2: InferMainActorInherited { + func f() { } // okay, 'f' is MainActor isolated, as is the requirement + @MainActor func g() { } // okay for the same reasons, but more explicitly +} + +@SomeGlobalActor +struct S3: InferenceConflict { + nonisolated func g() { } +} + +extension S3 { + func f() { } + // expected-error@-1{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot be used to satisfy main actor-isolated protocol requirement}} + //expected-note@-2{{add 'nonisolated' to 'f()' to make this instance method not isolated to the actor}} +}