mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -199,6 +199,10 @@ public:
|
|||||||
/// superclass requirement, 'T : C' cannot be satisfied.
|
/// superclass requirement, 'T : C' cannot be satisfied.
|
||||||
bool canBeSatisfied() const;
|
bool canBeSatisfied() const;
|
||||||
|
|
||||||
|
/// True if the requirement states a conformance to an invertible protocol
|
||||||
|
/// that is implied by default (such as `Copyable` or `Escapable`.
|
||||||
|
bool isInvertibleProtocolRequirement() const;
|
||||||
|
|
||||||
/// Linear order on requirements in a generic signature.
|
/// Linear order on requirements in a generic signature.
|
||||||
int compare(const Requirement &other) const;
|
int compare(const Requirement &other) const;
|
||||||
|
|
||||||
|
|||||||
@@ -1282,9 +1282,7 @@ void GenericSignatureImpl::getRequirementsWithInverses(
|
|||||||
|
|
||||||
// Filter out explicit conformances to invertible protocols.
|
// Filter out explicit conformances to invertible protocols.
|
||||||
for (auto req : getRequirements()) {
|
for (auto req : getRequirements()) {
|
||||||
if (req.getKind() == RequirementKind::Conformance &&
|
if (req.isInvertibleProtocolRequirement()) {
|
||||||
req.getFirstType()->is<GenericTypeParamType>() &&
|
|
||||||
req.getProtocolDecl()->getInvertibleProtocolKind()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,12 @@ bool Requirement::canBeSatisfied() const {
|
|||||||
llvm_unreachable("Bad requirement kind");
|
llvm_unreachable("Bad requirement kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Requirement::isInvertibleProtocolRequirement() const {
|
||||||
|
return getKind() == RequirementKind::Conformance
|
||||||
|
&& getFirstType()->is<GenericTypeParamType>()
|
||||||
|
&& getProtocolDecl()->getInvertibleProtocolKind();
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine the canonical ordering of requirements.
|
/// Determine the canonical ordering of requirements.
|
||||||
static unsigned getRequirementKindOrder(RequirementKind kind) {
|
static unsigned getRequirementKindOrder(RequirementKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
|||||||
@@ -2118,24 +2118,30 @@ namespace {
|
|||||||
|
|
||||||
// Compute the inverse requirements from the generic signature where the
|
// Compute the inverse requirements from the generic signature where the
|
||||||
// conformance occurs.
|
// conformance occurs.
|
||||||
SmallVector<Requirement, 2> scratchReqs;
|
SmallVector<Requirement, 2> condReqs;
|
||||||
SmallVector<InverseRequirement, 2> inverses;
|
SmallVector<InverseRequirement, 2> inverses;
|
||||||
if (auto genericSig =
|
if (auto genericSig =
|
||||||
normal->getDeclContext()->getGenericSignatureOfContext()) {
|
normal->getDeclContext()->getGenericSignatureOfContext()) {
|
||||||
genericSig->getRequirementsWithInverses(scratchReqs, inverses);
|
genericSig->getRequirementsWithInverses(condReqs, inverses);
|
||||||
scratchReqs.clear();
|
|
||||||
}
|
}
|
||||||
|
condReqs.clear();
|
||||||
|
|
||||||
auto condReqs = normal->getConditionalRequirements();
|
for (auto condReq : normal->getConditionalRequirements()) {
|
||||||
|
// We don't need to collect conditional requirements for invertible
|
||||||
|
// protocol requirements here, since they are encoded in the inverse
|
||||||
|
// list above.
|
||||||
|
if (!condReq.isInvertibleProtocolRequirement()) {
|
||||||
|
condReqs.push_back(condReq);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (condReqs.empty()) {
|
if (condReqs.empty()) {
|
||||||
// For a protocol P that conforms to another protocol, introduce a
|
// For a protocol P that conforms to another protocol, introduce a
|
||||||
// conditional requirement for that P's Self: P. This aligns with
|
// conditional requirement for that P's Self: P. This aligns with
|
||||||
// SILWitnessTable::enumerateWitnessTableConditionalConformances().
|
// SILWitnessTable::enumerateWitnessTableConditionalConformances().
|
||||||
if (auto selfProto = normal->getDeclContext()->getSelfProtocolDecl()) {
|
if (auto selfProto = normal->getDeclContext()->getSelfProtocolDecl()) {
|
||||||
auto selfType = selfProto->getSelfInterfaceType()->getCanonicalType();
|
auto selfType = selfProto->getSelfInterfaceType()->getCanonicalType();
|
||||||
scratchReqs.emplace_back(RequirementKind::Conformance, selfType,
|
condReqs.emplace_back(RequirementKind::Conformance, selfType,
|
||||||
selfProto->getDeclaredInterfaceType());
|
selfProto->getDeclaredInterfaceType());
|
||||||
condReqs = scratchReqs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (condReqs.empty() && inverses.empty())
|
if (condReqs.empty() && inverses.empty())
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// RUN: %target-swift-frontend -emit-ir %s | %FileCheck --check-prefix=IR %s
|
||||||
|
// RUN: %target-run-simple-swift | %FileCheck --check-prefix=EXEC %s
|
||||||
|
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
|
||||||
|
// The conformance descriptor for Optional: P ought to be encoded as if it
|
||||||
|
// were an unconditional conformance. We check this by checking that the
|
||||||
|
// global variable type is `%swift.protocol_conformance_descriptor`, indicating
|
||||||
|
// that there is no tail matter encoding conditional or inverted requirements.
|
||||||
|
|
||||||
|
// IR-LABEL: @"$sxSg4main1PABMc" ={{.*}} constant %swift.protocol_conformance_descriptor {
|
||||||
|
|
||||||
|
protocol P /*<implied> : Copyable*/ {
|
||||||
|
func p()
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Optional: P /*<implied> where T: Copyable */ {
|
||||||
|
func p() {
|
||||||
|
print("conforming optional \(self)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func cast<T>(value: T) -> (any P)? {
|
||||||
|
return value as? any P
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// EXEC: going to test
|
||||||
|
print("going to test")
|
||||||
|
|
||||||
|
// EXEC-NEXT: conforming optional Optional("test")
|
||||||
|
let x: String? = "test"
|
||||||
|
if let p = cast(value: x) {
|
||||||
|
p.p()
|
||||||
|
} else {
|
||||||
|
print("not a P")
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXEC-NEXT: done testing
|
||||||
|
print("done testing")
|
||||||
|
}
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user