Skip to content

Commit 179a125

Browse files
authored
Merge pull request #74604 from jckarter/conformance-descriptor-invertible-conditional-requirements
IRGen: Don't encode conditional requirements to Copyable as normal conformance requirements.
2 parents 026cb41 + 73e4c6f commit 179a125

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
@@ -1283,9 +1283,7 @@ void GenericSignatureImpl::getRequirementsWithInverses(
12831283

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

lib/AST/Requirement.cpp

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

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

lib/IRGen/GenProto.cpp

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

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

21422148
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)