diff --git a/include/swift/AST/Requirement.h b/include/swift/AST/Requirement.h index b82efc2314206..bcc49f1797269 100644 --- a/include/swift/AST/Requirement.h +++ b/include/swift/AST/Requirement.h @@ -198,6 +198,10 @@ class Requirement { /// '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; diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 8fbb654bf30f7..4dfa5d9c0cd3a 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -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() && - req.getProtocolDecl()->getInvertibleProtocolKind()) { + if (req.isInvertibleProtocolRequirement()) { continue; } diff --git a/lib/AST/Requirement.cpp b/lib/AST/Requirement.cpp index 4e6e9b7afe634..6547f61541be2 100644 --- a/lib/AST/Requirement.cpp +++ b/lib/AST/Requirement.cpp @@ -205,6 +205,12 @@ bool Requirement::canBeSatisfied() const { llvm_unreachable("Bad requirement kind"); } +bool Requirement::isInvertibleProtocolRequirement() const { + return getKind() == RequirementKind::Conformance + && getFirstType()->is() + && getProtocolDecl()->getInvertibleProtocolKind(); +} + /// Determine the canonical ordering of requirements. static unsigned getRequirementKindOrder(RequirementKind kind) { switch (kind) { diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 02d9f10ef2374..4bfaae534bd77 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2118,24 +2118,30 @@ namespace { // Compute the inverse requirements from the generic signature where the // conformance occurs. - SmallVector scratchReqs; + SmallVector condReqs; SmallVector inverses; if (auto genericSig = normal->getDeclContext()->getGenericSignatureOfContext()) { - genericSig->getRequirementsWithInverses(scratchReqs, inverses); - scratchReqs.clear(); + genericSig->getRequirementsWithInverses(condReqs, inverses); + } + condReqs.clear(); + + 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); + } } - - auto condReqs = normal->getConditionalRequirements(); 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()) diff --git a/test/IRGen/retrofitted-noncopyable-types-and-external-conformance-extensions.swift b/test/IRGen/retrofitted-noncopyable-types-and-external-conformance-extensions.swift new file mode 100644 index 0000000000000..c89f6bb63161a --- /dev/null +++ b/test/IRGen/retrofitted-noncopyable-types-and-external-conformance-extensions.swift @@ -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 /* : Copyable*/ { + func p() +} + +extension Optional: P /* where T: Copyable */ { + func p() { + print("conforming optional \(self)") + } +} + +@inline(never) +func cast(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()