Skip to content

Commit d8860bc

Browse files
committed
[Concurrency] TildeSendable: Lift the check up to cover isolated types
If a type is suppressing `~Sendable` global-actor isolation shouldn't make it `Sendable` and the compiler should diagnose cases were `Sendable` comes from an isolated protocol.
1 parent b6291e6 commit d8860bc

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7375,6 +7375,24 @@ bool swift::checkSendableConformance(
73757375
return false;
73767376
}
73777377

7378+
// Sendable supression allows conditional conformances only.
7379+
if (nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
7380+
bool hasUnconditionalConformance = false;
7381+
if (auto *normalConf = dyn_cast<NormalProtocolConformance>(conformance)) {
7382+
hasUnconditionalConformance =
7383+
normalConf->getConditionalRequirements().empty();
7384+
}
7385+
7386+
if (hasUnconditionalConformance) {
7387+
if (!isImplicitSendableCheck(check)) {
7388+
auto *conformanceDecl =
7389+
conformanceDC->getAsDecl() ? conformanceDC->getAsDecl() : nominal;
7390+
conformanceDecl->diagnose(diag::non_sendable_type_suppressed);
7391+
}
7392+
return true;
7393+
}
7394+
}
7395+
73787396
// Global-actor-isolated types can be Sendable. We do not check the
73797397
// instance data because it's all isolated to the global actor.
73807398
switch (getActorIsolation(nominal)) {
@@ -7458,24 +7476,6 @@ bool swift::checkSendableConformance(
74587476
if (wasImplied)
74597477
conformanceDC = nominal;
74607478

7461-
// Sendable supression allows conditional conformances only.
7462-
if (nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
7463-
bool hasUnconditionalConformance = false;
7464-
if (auto *normalConf = dyn_cast<NormalProtocolConformance>(conformance)) {
7465-
hasUnconditionalConformance =
7466-
normalConf->getConditionalRequirements().empty();
7467-
}
7468-
7469-
if (hasUnconditionalConformance) {
7470-
if (!isImplicitSendableCheck(check)) {
7471-
auto *conformanceDecl =
7472-
conformanceDC->getAsDecl() ? conformanceDC->getAsDecl() : nominal;
7473-
conformanceDecl->diagnose(diag::non_sendable_type_suppressed);
7474-
}
7475-
return true;
7476-
}
7477-
}
7478-
74797479
return checkSendableInstanceStorage(nominal, conformanceDC, check);
74807480
}
74817481

test/Sema/tilde_sendable.swift

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ extension InExt: ~Sendable { // expected-error {{conformance to inferrable proto
2727
func test<T: ~Sendable>(_: T) {} // expected-error {{conformance to 'Sendable' can only be suppressed on structs, classes, and enums}}
2828
func test<Q>(other: Q) where Q: ~Sendable {} // expected-error {{type 'Sendable' cannot be suppressed}}
2929

30+
func testSendable<T: Sendable>(_: T) {}
31+
32+
3033
struct Generic<T: ~Sendable> { // expected-error {{conformance to 'Sendable' can only be suppressed on structs, classes, and enums}}
3134
var x: T
3235
}
@@ -47,10 +50,8 @@ do {
4750
// expected-error@-1 {{cannot both conform to and suppress conformance to 'Sendable'}}
4851
}
4952

50-
func check<T: Sendable>(_: T) {}
51-
52-
check(NonSendable()) // expected-warning {{type 'NonSendable' does not conform to the 'Sendable' protocol}}
53-
check(NoInference()) // Ok
53+
testSendable(NonSendable()) // expected-warning {{type 'NonSendable' does not conform to the 'Sendable' protocol}}
54+
testSendable(NoInference()) // Ok
5455
}
5556

5657
func takesSendable<T: Sendable>(_: T) {}
@@ -91,3 +92,31 @@ extension H: Sendable where T: Sendable, U: Sendable { }
9192

9293
takesSendable(H(t: "", u: 42))
9394
takesSendable(H(t: "", u: MyValue())) // expected-warning {{type 'MyValue' does not conform to the 'Sendable' protocol}}
95+
96+
@MainActor
97+
protocol IsolatedP {
98+
}
99+
100+
@MainActor
101+
protocol IsolatedSendableP: Sendable {
102+
}
103+
104+
do {
105+
struct S1: ~Sendable, W {
106+
// expected-error@-1 {{cannot both conform to and suppress conformance to 'Sendable'}}
107+
}
108+
109+
struct S2: IsolatedP, ~Sendable { // Ok (because isolated protocol is not Sendable unless explicitly stated)
110+
}
111+
112+
struct S3: IsolatedSendableP, ~Sendable {
113+
// expected-error@-1 {{cannot both conform to and suppress conformance to 'Sendable'}}
114+
}
115+
116+
@MainActor
117+
class IsolatedC: ~Sendable {}
118+
// expected-note@-1 {{class 'IsolatedC' explicitly suppresses conformance to 'Sendable' protocol}}
119+
120+
testSendable(IsolatedC())
121+
// expected-warning@-1 {{type 'IsolatedC' does not conform to the 'Sendable' protocol}}
122+
}

0 commit comments

Comments
 (0)