Skip to content

Commit d089f83

Browse files
authored
Merge pull request #74605 from jckarter/conformance-descriptor-invertible-conditional-requirements-6.0
[6.0] IRGen: Don't encode conditional requirements to Copyable as normal conformance requirement.
2 parents e296735 + 7abe475 commit d089f83

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)