Skip to content

Commit c446515

Browse files
committed
Sema: Implied 'Sendable' conformance should be unconditional
A conditional conformance to a protocol does not usually imply a conformance to the protocol's inherited protocols, because we have no way to guess what the conditional requirements should be. A carveout was added for 'Sendable', so that protocols could inherit from 'Sendable' retroactively. However, the 'Sendable' conformance would become conditional, which causes us to reject a _second_ conditional conformance to such a protocol: struct G<T> {} protocol P: Sendable {} protocol Q: Sendable {} extension G: P where T: P {} extension G: Q where T: Q {} To make this work, tweak the code so that an implied conformance has the same generic signature as the conforming type, that is, we force it to be unconditional. Fixes rdar://122754849 Fixes #71544
1 parent de144e9 commit c446515

File tree

4 files changed

+36
-1
lines changed

4 files changed

+36
-1
lines changed

lib/AST/ConformanceLookup.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@ LookupConformanceInModuleRequest::evaluate(
717717
// specialized type.
718718
auto *normalConf = cast<NormalProtocolConformance>(conformance);
719719
auto *conformanceDC = normalConf->getDeclContext();
720+
721+
if (normalConf->getSourceKind() == ConformanceEntryKind::Implied &&
722+
normalConf->getProtocol()->isSpecificProtocol(KnownProtocolKind::Sendable)) {
723+
conformanceDC = conformanceDC->getSelfNominalTypeDecl();
724+
}
725+
720726
auto subMap = type->getContextSubstitutionMap(mod, conformanceDC);
721727
return ProtocolConformanceRef(
722728
ctx.getSpecializedConformance(type, normalConf, subMap));

lib/AST/ProtocolConformance.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ GenericSignature ProtocolConformance::getGenericSignature() const {
230230
case ProtocolConformanceKind::Self:
231231
// If we have a normal or inherited protocol conformance, look for its
232232
// generic signature.
233+
if (getSourceKind() == ConformanceEntryKind::Implied &&
234+
getProtocol()->isSpecificProtocol(KnownProtocolKind::Sendable)) {
235+
return getDeclContext()->getSelfNominalTypeDecl()->getGenericSignature();
236+
}
233237
return getDeclContext()->getGenericSignatureOfContext();
234238

235239
case ProtocolConformanceKind::Builtin:
@@ -405,7 +409,7 @@ ConditionalRequirementsRequest::evaluate(Evaluator &evaluator,
405409
return {};
406410
}
407411

408-
const auto extensionSig = ext->getGenericSignature();
412+
const auto extensionSig = NPC->getGenericSignature();
409413

410414
// The extension signature should be a superset of the type signature, meaning
411415
// every thing in the type signature either is included too or is implied by

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6040,6 +6040,8 @@ bool swift::checkSendableConformance(
60406040
}
60416041
}
60426042

6043+
if (conformance->getSourceKind() == ConformanceEntryKind::Implied)
6044+
conformanceDC = nominal;
60436045
return checkSendableInstanceStorage(nominal, conformanceDC, check);
60446046
}
60456047

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
2+
// RUN: %target-swift-emit-silgen %s -swift-version 5
3+
4+
protocol P: Sendable {}
5+
protocol Q: Sendable {}
6+
7+
struct One<T> { // expected-note {{consider making generic parameter 'T' conform to the 'Sendable' protocol}}
8+
var t: T // expected-warning {{stored property 't' of 'Sendable'-conforming generic struct 'One' has non-sendable type 'T'; this is an error in the Swift 6 language mode}}
9+
}
10+
11+
extension One: P where T: P {}
12+
13+
struct Both<T> { // expected-note {{consider making generic parameter 'T' conform to the 'Sendable' protocol}}
14+
var t: T // expected-warning {{stored property 't' of 'Sendable'-conforming generic struct 'Both' has non-sendable type 'T'; this is an error in the Swift 6 language mode}}
15+
}
16+
17+
extension Both: P where T: P {}
18+
extension Both: Q where T: Q {}
19+
20+
func takesSendable<T: Sendable>(_: T) {}
21+
22+
takesSendable(One<Int>(t: 3))
23+
takesSendable(Both<Int>(t: 3))

0 commit comments

Comments
 (0)