Skip to content

Commit 73e4c6f

Browse files
committed
IRGen: Don't encode conditional requirements to Copyable as normal conformance requirements.
For new runtimes, this is redundant with the invertible requirement encoding, and for old runtimes, this breaks dynamic conformance checking because Copyable and Escapable aren't real protocols on those older runtimes. Fixes rdar://129857284.
1 parent b7b93a1 commit 73e4c6f

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

include/swift/AST/Requirement.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ class Requirement {
198198
/// 'T : C' can be satisfied; however, if 'T' already has an unrelated
199199
/// superclass requirement, 'T : C' cannot be satisfied.
200200
bool canBeSatisfied() const;
201+
202+
/// True if the requirement states a conformance to an invertible protocol
203+
/// that is implied by default (such as `Copyable` or `Escapable`.
204+
bool isInvertibleProtocolRequirement() const;
201205

202206
/// Linear order on requirements in a generic signature.
203207
int compare(const Requirement &other) const;

lib/AST/GenericSignature.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,9 +1282,7 @@ void GenericSignatureImpl::getRequirementsWithInverses(
12821282

12831283
// Filter out explicit conformances to invertible protocols.
12841284
for (auto req : getRequirements()) {
1285-
if (req.getKind() == RequirementKind::Conformance &&
1286-
req.getFirstType()->is<GenericTypeParamType>() &&
1287-
req.getProtocolDecl()->getInvertibleProtocolKind()) {
1285+
if (req.isInvertibleProtocolRequirement()) {
12881286
continue;
12891287
}
12901288

lib/AST/Requirement.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,12 @@ bool Requirement::canBeSatisfied() const {
205205
llvm_unreachable("Bad requirement kind");
206206
}
207207

208+
bool Requirement::isInvertibleProtocolRequirement() const {
209+
return getKind() == RequirementKind::Conformance
210+
&& getFirstType()->is<GenericTypeParamType>()
211+
&& getProtocolDecl()->getInvertibleProtocolKind();
212+
}
213+
208214
/// Determine the canonical ordering of requirements.
209215
static unsigned getRequirementKindOrder(RequirementKind kind) {
210216
switch (kind) {

lib/IRGen/GenProto.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,24 +2118,30 @@ namespace {
21182118

21192119
// Compute the inverse requirements from the generic signature where the
21202120
// conformance occurs.
2121-
SmallVector<Requirement, 2> scratchReqs;
2121+
SmallVector<Requirement, 2> condReqs;
21222122
SmallVector<InverseRequirement, 2> inverses;
21232123
if (auto genericSig =
21242124
normal->getDeclContext()->getGenericSignatureOfContext()) {
2125-
genericSig->getRequirementsWithInverses(scratchReqs, inverses);
2126-
scratchReqs.clear();
2125+
genericSig->getRequirementsWithInverses(condReqs, inverses);
2126+
}
2127+
condReqs.clear();
2128+
2129+
for (auto condReq : normal->getConditionalRequirements()) {
2130+
// We don't need to collect conditional requirements for invertible
2131+
// protocol requirements here, since they are encoded in the inverse
2132+
// list above.
2133+
if (!condReq.isInvertibleProtocolRequirement()) {
2134+
condReqs.push_back(condReq);
2135+
}
21272136
}
2128-
2129-
auto condReqs = normal->getConditionalRequirements();
21302137
if (condReqs.empty()) {
21312138
// For a protocol P that conforms to another protocol, introduce a
21322139
// conditional requirement for that P's Self: P. This aligns with
21332140
// SILWitnessTable::enumerateWitnessTableConditionalConformances().
21342141
if (auto selfProto = normal->getDeclContext()->getSelfProtocolDecl()) {
21352142
auto selfType = selfProto->getSelfInterfaceType()->getCanonicalType();
2136-
scratchReqs.emplace_back(RequirementKind::Conformance, selfType,
2143+
condReqs.emplace_back(RequirementKind::Conformance, selfType,
21372144
selfProto->getDeclaredInterfaceType());
2138-
condReqs = scratchReqs;
21392145
}
21402146

21412147
if (condReqs.empty() && inverses.empty())
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swift-frontend -emit-ir %s | %FileCheck --check-prefix=IR %s
2+
// RUN: %target-run-simple-swift | %FileCheck --check-prefix=EXEC %s
3+
4+
// REQUIRES: executable_test
5+
6+
// The conformance descriptor for Optional: P ought to be encoded as if it
7+
// were an unconditional conformance. We check this by checking that the
8+
// global variable type is `%swift.protocol_conformance_descriptor`, indicating
9+
// that there is no tail matter encoding conditional or inverted requirements.
10+
11+
// IR-LABEL: @"$sxSg4main1PABMc" ={{.*}} constant %swift.protocol_conformance_descriptor {
12+
13+
protocol P /*<implied> : Copyable*/ {
14+
func p()
15+
}
16+
17+
extension Optional: P /*<implied> where T: Copyable */ {
18+
func p() {
19+
print("conforming optional \(self)")
20+
}
21+
}
22+
23+
@inline(never)
24+
func cast<T>(value: T) -> (any P)? {
25+
return value as? any P
26+
}
27+
28+
func main() {
29+
// EXEC: going to test
30+
print("going to test")
31+
32+
// EXEC-NEXT: conforming optional Optional("test")
33+
let x: String? = "test"
34+
if let p = cast(value: x) {
35+
p.p()
36+
} else {
37+
print("not a P")
38+
}
39+
40+
// EXEC-NEXT: done testing
41+
print("done testing")
42+
}
43+
main()

0 commit comments

Comments
 (0)