Skip to content

Commit ae4662d

Browse files
committed
[Sema] Diagnose places where @preconcurrency attribute on conformance has no effect
1 parent d96c4f5 commit ae4662d

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5626,6 +5626,8 @@ ERROR(unchecked_not_inheritance_clause,none,
56265626
ERROR(unchecked_not_existential,none,
56275627
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))
56285628

5629+
WARNING(preconcurrency_conformance_not_used,none,
5630+
"@preconcurrency attribute on conformance to %0 has no effect", (Type))
56295631
ERROR(preconcurrency_not_inheritance_clause,none,
56305632
"'preconcurrency' attribute only applies in inheritance clauses", ())
56315633
ERROR(preconcurrency_not_existential,none,

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5281,6 +5281,7 @@ hasInvalidTypeInConformanceContext(const ValueDecl *requirement,
52815281
}
52825282

52835283
void ConformanceChecker::resolveValueWitnesses() {
5284+
bool usesPreconcurrencyConformance = false;
52845285
for (auto *requirement : Proto->getProtocolRequirements()) {
52855286
// Associated type requirements handled elsewhere.
52865287
if (isa<TypeDecl>(requirement))
@@ -5299,6 +5300,15 @@ void ConformanceChecker::resolveValueWitnesses() {
52995300
// Check actor isolation. If we need to enter into the actor's
53005301
// isolation within the witness thunk, record that.
53015302
if (auto enteringIsolation = checkActorIsolation(requirement, witness)) {
5303+
// Only @preconcurrency conformances allow entering isolation
5304+
// when neither requirement nor witness are async by adding a
5305+
// runtime precondition that witness is always called on the
5306+
// expected executor.
5307+
if (Conformance->isPreconcurrency()) {
5308+
usesPreconcurrencyConformance =
5309+
!isAsyncDecl(requirement) && !isAsyncDecl(witness);
5310+
}
5311+
53025312
Conformance->overrideWitness(
53035313
requirement,
53045314
Conformance->getWitnessUncached(requirement)
@@ -5432,6 +5442,12 @@ void ConformanceChecker::resolveValueWitnesses() {
54325442
}
54335443
}
54345444

5445+
if (Conformance->isPreconcurrency() && !usesPreconcurrencyConformance) {
5446+
DC->getASTContext().Diags.diagnose(
5447+
Conformance->getLoc(), diag::preconcurrency_conformance_not_used,
5448+
Proto->getDeclaredInterfaceType());
5449+
}
5450+
54355451
// Finally, check some ad-hoc protocol requirements.
54365452
//
54375453
// These protocol requirements are not expressible in Swift today, but as

test/Concurrency/preconcurrency_conformances.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ do {
1010
class K {}
1111

1212
struct A : @preconcurrency Q {} // Ok
13+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'Q' has no effect}}
14+
1315
struct B : @preconcurrency K {
1416
// expected-error@-1 {{'preconcurrency' attribute cannot apply to non-protocol type 'K'}}
1517
var x: @preconcurrency Int
@@ -29,6 +31,7 @@ protocol InvalidUseOfPreconcurrencyAttr : @preconcurrency Q {
2931

3032
struct TestPreconcurrencyAttr {}
3133
extension TestPreconcurrencyAttr : @preconcurrency Q { // Ok
34+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'Q' has no effect}}
3235
}
3336

3437
class NonSendable {}
@@ -91,6 +94,7 @@ protocol Initializable {
9194
}
9295

9396
final class K : @preconcurrency Initializable {
97+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'Initializable' has no effect}}
9498
init() {} // Ok
9599
}
96100

@@ -122,6 +126,8 @@ protocol WithIndividuallyIsolatedRequirements {
122126
do {
123127
@MainActor
124128
struct TestExplicitGlobalActorAttrs : @preconcurrency WithIndividuallyIsolatedRequirements {
129+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'WithIndividuallyIsolatedRequirements' has no effect}}
130+
125131
var a: Int = 42
126132

127133
@MainActor var b: Int {
@@ -146,10 +152,20 @@ protocol WithNonIsolated {
146152

147153
do {
148154
class TestExplicitOtherIsolation : @preconcurrency WithNonIsolated {
155+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'WithNonIsolated' has no effect}}
156+
149157
@GlobalActor var prop: Int = 42
150158
// expected-warning@-1 {{global actor 'GlobalActor'-isolated property 'prop' cannot be used to satisfy main actor-isolated protocol requirement}}
151159

152160
@MainActor func test() {}
153161
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy nonisolated protocol requirement}}
154162
}
155163
}
164+
165+
do {
166+
class InferredGlobalActorAttrs : @preconcurrency WithNonIsolated {
167+
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'WithNonIsolated' has no effect}}
168+
var prop: Int = 42
169+
func test() {}
170+
}
171+
}

0 commit comments

Comments
 (0)