Skip to content

Commit d96c4f5

Browse files
committed
[Sema] @preconcurrency conformances have no effect for protocols that adopted concurrency
Don't treat isolated or explicitly `nonisolated` requirements as preconcurrency because in that case we consider protocol as concurrency adopter.
1 parent e5d54e3 commit d96c4f5

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3094,6 +3094,14 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
30943094
getDeclRefInContext(witness), witness->getLoc(), DC, llvm::None,
30953095
llvm::None, llvm::None, requirementIsolation);
30963096
bool sameConcurrencyDomain = false;
3097+
// If the requirement is isolated (explicitly or implicitly) or
3098+
// explicitly marked as `nonisolated` it means that the protocol
3099+
// has adopted concurrency and `@preconcurrency` doesn't apply.
3100+
bool isPreconcurrency =
3101+
Conformance->isPreconcurrency() &&
3102+
!(requirementIsolation.isActorIsolated() ||
3103+
requirement->getAttrs().hasAttribute<NonisolatedAttr>());
3104+
30973105
switch (refResult) {
30983106
case ActorReferenceResult::SameConcurrencyDomain:
30993107
// If the witness has distributed-actor isolation, we have extra
@@ -3184,7 +3192,7 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
31843192

31853193
// If we aren't missing anything or this is a witness to a `@preconcurrency`
31863194
// conformance, do a Sendable check and move on.
3187-
if (!missingOptions || Conformance->isPreconcurrency()) {
3195+
if (!missingOptions || isPreconcurrency) {
31883196
// FIXME: Disable Sendable checking when the witness is an initializer
31893197
// that is explicitly marked nonisolated.
31903198
if (isa<ConstructorDecl>(witness) &&
@@ -3216,7 +3224,7 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
32163224
return refResult.isolation;
32173225

32183226
// Always treat `@preconcurrency` witnesses as isolated.
3219-
if (Conformance->isPreconcurrency() &&
3227+
if (isPreconcurrency &&
32203228
missingOptions.contains(MissingFlags::RequirementAsync))
32213229
return refResult.isolation;
32223230
}

test/Concurrency/preconcurrency_conformances.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -enable-experimental-feature PreconcurrencyConformances -strict-concurrency=complete -verify-additional-prefix complete-tns-
1+
// RUN: %target-swift-frontend -swift-version 5 -disable-availability-checking %s -emit-sil -o /dev/null -verify -enable-experimental-feature PreconcurrencyConformances -strict-concurrency=complete -verify-additional-prefix complete-tns-
22

33
// REQUIRES: concurrency
44
// REQUIRES: asserts
@@ -104,3 +104,52 @@ struct TestConditional<T> {}
104104
extension TestConditional : @preconcurrency WithAssoc where T == Int {
105105
@MainActor func test() -> T { 42 } // Ok
106106
}
107+
108+
@globalActor
109+
struct GlobalActor {
110+
static var shared: MyActor = MyActor()
111+
}
112+
113+
protocol WithIndividuallyIsolatedRequirements {
114+
@MainActor var a: Int { get set }
115+
@GlobalActor var b: Int { get set }
116+
// expected-note@-1 {{'b' declared here}}
117+
118+
@GlobalActor func test()
119+
// expected-note@-1 {{mark the protocol requirement 'test()' 'async' to allow actor-isolated conformances}}
120+
}
121+
122+
do {
123+
@MainActor
124+
struct TestExplicitGlobalActorAttrs : @preconcurrency WithIndividuallyIsolatedRequirements {
125+
var a: Int = 42
126+
127+
@MainActor var b: Int {
128+
// expected-warning@-1 {{main actor-isolated property 'b' cannot be used to satisfy global actor 'GlobalActor'-isolated protocol requirement}}
129+
get { 0 }
130+
set {}
131+
}
132+
133+
@MainActor func test() {
134+
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy global actor 'GlobalActor'-isolated protocol requirement}}
135+
}
136+
}
137+
}
138+
139+
@MainActor
140+
protocol WithNonIsolated {
141+
var prop: Int { get set }
142+
// expected-note@-1 {{'prop' declared here}}
143+
nonisolated func test()
144+
// expected-note@-1 {{mark the protocol requirement 'test()' 'async' to allow actor-isolated conformances}}
145+
}
146+
147+
do {
148+
class TestExplicitOtherIsolation : @preconcurrency WithNonIsolated {
149+
@GlobalActor var prop: Int = 42
150+
// expected-warning@-1 {{global actor 'GlobalActor'-isolated property 'prop' cannot be used to satisfy main actor-isolated protocol requirement}}
151+
152+
@MainActor func test() {}
153+
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy nonisolated protocol requirement}}
154+
}
155+
}

0 commit comments

Comments
 (0)