Skip to content

Commit f2c5e44

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

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
@@ -5638,6 +5638,8 @@ ERROR(unchecked_not_inheritance_clause,none,
56385638
ERROR(unchecked_not_existential,none,
56395639
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))
56405640

5641+
WARNING(preconcurrency_conformance_not_used,none,
5642+
"@preconcurrency attribute on conformance to %0 has no effect", (Type))
56415643
ERROR(preconcurrency_not_inheritance_clause,none,
56425644
"'preconcurrency' attribute only applies in inheritance clauses", ())
56435645
ERROR(preconcurrency_not_existential,none,

lib/Sema/TypeCheckProtocol.cpp

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

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

5461+
if (Conformance->isPreconcurrency() && !usesPreconcurrencyConformance) {
5462+
DC->getASTContext().Diags.diagnose(
5463+
Conformance->getLoc(), diag::preconcurrency_conformance_not_used,
5464+
Proto->getDeclaredInterfaceType());
5465+
}
5466+
54515467
// Finally, check some ad-hoc protocol requirements.
54525468
//
54535469
// 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)