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:
@@ -198,6 +198,10 @@ public:
|
||||
/// 'T : C' can be satisfied; however, if 'T' already has an unrelated
|
||||
/// superclass requirement, 'T : C' cannot be satisfied.
|
||||
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.
|
||||
int compare(const Requirement &other) const;
|
||||
|
||||
@@ -1282,9 +1282,7 @@ void GenericSignatureImpl::getRequirementsWithInverses(
|
||||
|
||||
// Filter out explicit conformances to invertible protocols.
|
||||
for (auto req : getRequirements()) {
|
||||
if (req.getKind() == RequirementKind::Conformance &&
|
||||
req.getFirstType()->is<GenericTypeParamType>() &&
|
||||
req.getProtocolDecl()->getInvertibleProtocolKind()) {
|
||||
if (req.isInvertibleProtocolRequirement()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +205,12 @@ bool Requirement::canBeSatisfied() const {
|
||||
llvm_unreachable("Bad requirement kind");
|
||||
}
|
||||
|
||||
bool Requirement::isInvertibleProtocolRequirement() const {
|
||||
return getKind() == RequirementKind::Conformance
|
||||
&& getFirstType()->is<GenericTypeParamType>()
|
||||
&& getProtocolDecl()->getInvertibleProtocolKind();
|
||||
}
|
||||
|
||||
/// Determine the canonical ordering of requirements.
|
||||
static unsigned getRequirementKindOrder(RequirementKind kind) {
|
||||
switch (kind) {
|
||||
|
||||
@@ -2118,24 +2118,30 @@ namespace {
|
||||
|
||||
// Compute the inverse requirements from the generic signature where the
|
||||
// conformance occurs.
|
||||
SmallVector<Requirement, 2> scratchReqs;
|
||||
SmallVector<Requirement, 2> condReqs;
|
||||
SmallVector<InverseRequirement, 2> inverses;
|
||||
if (auto genericSig =
|
||||
normal->getDeclContext()->getGenericSignatureOfContext()) {
|
||||
genericSig->getRequirementsWithInverses(scratchReqs, inverses);
|
||||
scratchReqs.clear();
|
||||
genericSig->getRequirementsWithInverses(condReqs, inverses);
|
||||
}
|
||||
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()) {
|
||||
// For a protocol P that conforms to another protocol, introduce a
|
||||
// conditional requirement for that P's Self: P. This aligns with
|
||||
// SILWitnessTable::enumerateWitnessTableConditionalConformances().
|
||||
if (auto selfProto = normal->getDeclContext()->getSelfProtocolDecl()) {
|
||||
auto selfType = selfProto->getSelfInterfaceType()->getCanonicalType();
|
||||
scratchReqs.emplace_back(RequirementKind::Conformance, selfType,
|
||||
condReqs.emplace_back(RequirementKind::Conformance, selfType,
|
||||
selfProto->getDeclaredInterfaceType());
|
||||
condReqs = scratchReqs;
|
||||
}
|
||||
|
||||
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