mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Concurrency] Allow conditionally conforming to Sendable when conformance is suppressed
For consistency with invertible protocols using `~Sendable` should
only prohibit use of unconditional extensions.
For example:
```swift
struct G<T>: ~Sendable {}
```
The following (unconditional) extension is rejected:
```
extension G: Sendable {} // error: cannot both conform to and suppress conformance to 'Sendable'
```
But conditional on `T` is accepted:
```
extension G: Sendable where T: Sendable {} // Ok!
```
This commit is contained in:
@@ -7180,14 +7180,6 @@ static bool checkSendableInstanceStorage(
|
||||
}
|
||||
}
|
||||
|
||||
if (nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
|
||||
auto *conformanceDecl = dc->getAsDecl() ? dc->getAsDecl() : nominal;
|
||||
if (!isImplicitSendableCheck(check)) {
|
||||
conformanceDecl->diagnose(diag::non_sendable_type_suppressed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stored properties of structs and classes must have
|
||||
// Sendable-conforming types.
|
||||
class Visitor: public StorageVisitor {
|
||||
@@ -7462,6 +7454,25 @@ bool swift::checkSendableConformance(
|
||||
// and not some (possibly constrained) extension.
|
||||
if (wasImplied)
|
||||
conformanceDC = nominal;
|
||||
|
||||
// Sendable supression allows conditional conformances only.
|
||||
if (nominal->suppressesConformance(KnownProtocolKind::Sendable)) {
|
||||
bool hasUnconditionalConformance = false;
|
||||
if (auto *normalConf = dyn_cast<NormalProtocolConformance>(conformance)) {
|
||||
hasUnconditionalConformance =
|
||||
normalConf->getConditionalRequirements().empty();
|
||||
}
|
||||
|
||||
if (hasUnconditionalConformance) {
|
||||
if (!isImplicitSendableCheck(check)) {
|
||||
auto *conformanceDecl =
|
||||
conformanceDC->getAsDecl() ? conformanceDC->getAsDecl() : nominal;
|
||||
conformanceDecl->diagnose(diag::non_sendable_type_suppressed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return checkSendableInstanceStorage(nominal, conformanceDC, check);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,3 +33,18 @@ protocol P {
|
||||
public struct S: P, ~Sendable {
|
||||
public let x: Int
|
||||
}
|
||||
|
||||
// CHECK: #if compiler(>=5.3) && $TildeSendable
|
||||
// CHECK: public struct B<T> : ~Swift.Sendable {
|
||||
// CHECK: }
|
||||
// CHECK: #else
|
||||
// CHECK: public struct B<T> {
|
||||
// CHECK: }
|
||||
// CHECK: #endif
|
||||
public struct B<T>: ~Sendable {
|
||||
}
|
||||
|
||||
// CHECK: extension Library.B : Swift.Sendable where T : Swift.Sendable {
|
||||
// CHECK: }
|
||||
extension B: Sendable where T: Sendable {
|
||||
}
|
||||
|
||||
@@ -52,3 +52,42 @@ do {
|
||||
check(NonSendable()) // expected-warning {{type 'NonSendable' does not conform to the 'Sendable' protocol}}
|
||||
check(NoInference()) // Ok
|
||||
}
|
||||
|
||||
func takesSendable<T: Sendable>(_: T) {}
|
||||
|
||||
class MyValue {} // expected-note 2 {{class 'MyValue' does not conform to the 'Sendable' protocol}}
|
||||
|
||||
public struct D: ~Sendable {
|
||||
}
|
||||
|
||||
extension D: Sendable {} // expected-error {{cannot both conform to and suppress conformance to 'Sendable'}}
|
||||
|
||||
takesSendable(D())
|
||||
|
||||
public struct F<T>: ~Sendable {
|
||||
let x: T
|
||||
}
|
||||
|
||||
extension F: Sendable where T: Sendable { }
|
||||
|
||||
takesSendable(F(x: 42))
|
||||
|
||||
public struct G<T, U>: ~Sendable { // expected-note {{making generic parameter 'U' conform to the 'Sendable' protocol}}
|
||||
let t: T
|
||||
let u: U // expected-warning {{stored property 'u' of 'Sendable'-conforming generic struct 'G' has non-Sendable type 'U'}}
|
||||
}
|
||||
|
||||
extension G: Sendable where T: Sendable { }
|
||||
|
||||
takesSendable(G(t: "", u: 42))
|
||||
takesSendable(G(t: MyValue(), u: 0)) // expected-warning {{type 'MyValue' does not conform to the 'Sendable' protocol}}
|
||||
|
||||
public struct H<T, U>: ~Sendable {
|
||||
let t: T
|
||||
let u: U
|
||||
}
|
||||
|
||||
extension H: Sendable where T: Sendable, U: Sendable { }
|
||||
|
||||
takesSendable(H(t: "", u: 42))
|
||||
takesSendable(H(t: "", u: MyValue())) // expected-warning {{type 'MyValue' does not conform to the 'Sendable' protocol}}
|
||||
|
||||
Reference in New Issue
Block a user