Skip to content

Commit d93111c

Browse files
committed
IRGen: omit conditional reqs for invertible protos
1 parent d94d146 commit d93111c

File tree

5 files changed

+124
-4
lines changed

5 files changed

+124
-4
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,20 @@ class GenericSignature {
213213
SmallVector<Requirement, 4>
214214
requirementsNotSatisfiedBy(GenericSignature otherSig) const;
215215

216+
/// Return the requirements of this generic signature that are not also
217+
/// satisfied by \c otherSig.
218+
///
219+
/// Requirements for invertible protocols are omitted. Instead, their absence
220+
/// in this generic signature is noted in the \c inverses output.
221+
///
222+
/// \param otherSig Another generic signature whose generic parameters are
223+
/// equivalent to or a subset of the generic parameters in this signature, and
224+
/// whose inverses are a superset of the inverses in this generic signature.
225+
void requirementsAndInversesWhenExtending(
226+
GenericSignature otherSig,
227+
SmallVector<Requirement, 2> &result,
228+
SmallVector<InverseRequirement, 2> &inverses) const;
229+
216230
/// Return the reduced version of the given type under this generic
217231
/// signature.
218232
CanType getReducedType(Type type) const;
@@ -528,6 +542,20 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
528542
SmallVector<Requirement, 4>
529543
requirementsNotSatisfiedBy(GenericSignature otherSig) const;
530544

545+
/// Return the requirements of this generic signature that are not also
546+
/// satisfied by \c otherSig.
547+
///
548+
/// Requirements for invertible protocols are omitted. Instead, their absence
549+
/// in this generic signature is noted in the \c inverses output.
550+
///
551+
/// \param otherSig Another generic signature whose generic parameters are
552+
/// equivalent to or a subset of the generic parameters in this signature, and
553+
/// whose inverses are a superset of the inverses in this generic signature.
554+
void requirementsAndInversesWhenExtending(
555+
GenericSignature otherSig,
556+
SmallVector<Requirement, 2> &reqs,
557+
SmallVector<InverseRequirement, 2> &inverses) const;
558+
531559
/// Return the reduced version of the given type under this generic
532560
/// signature.
533561
CanType getReducedType(Type type) const;

include/swift/AST/ProtocolConformance.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,13 @@ class NormalProtocolConformance : public RootProtocolConformance,
595595
llvm::Optional<ArrayRef<Requirement>>
596596
getConditionalRequirementsIfAvailable() const;
597597

598+
/// Get any additional requirements that are required for this conformance to
599+
/// be satisfied, and inverses, which indicate generic parameters that do
600+
/// *not* require conformance to an invertible protocol.
601+
void getConditionalRequirementsWithInverses(
602+
SmallVector<Requirement, 2> &requirements,
603+
SmallVector<InverseRequirement, 2> &inverses) const;
604+
598605
/// Retrieve the state of this conformance.
599606
ProtocolConformanceState getState() const {
600607
return static_cast<ProtocolConformanceState>(

lib/AST/GenericSignature.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,52 @@ SmallVector<Requirement, 4> GenericSignatureImpl::requirementsNotSatisfiedBy(
479479
return result;
480480
}
481481

482+
void GenericSignature::requirementsAndInversesWhenExtending(
483+
GenericSignature otherSig,
484+
SmallVector<Requirement, 2> &result,
485+
SmallVector<InverseRequirement, 2> &inverses) const {
486+
assert(!isNull()); // what to do about a null generic signature?
487+
return getPointer()->requirementsAndInversesWhenExtending(otherSig,
488+
result,
489+
inverses);
490+
}
491+
492+
493+
void GenericSignatureImpl::requirementsAndInversesWhenExtending(
494+
GenericSignature otherSig,
495+
SmallVector<Requirement, 2> &result,
496+
SmallVector<InverseRequirement, 2> &inverses) const {
497+
SmallVector<Requirement, 2> reqs;
498+
getRequirementsWithInverses(reqs, inverses);
499+
500+
// If the signatures match by pointer, all requirements are satisfied.
501+
if (otherSig.getPointer() == this) return;
502+
503+
// If there is no other signature, no requirements are satisfied.
504+
if (!otherSig) {
505+
result.append(reqs.begin(), reqs.end());
506+
return;
507+
}
508+
509+
#ifndef NDEBUG
510+
{
511+
// Check that otherSig has the same or more inverses than this signature.
512+
SmallVector<Requirement, 2> otherReqs;
513+
SmallVector<InverseRequirement, 2> otherInverses;
514+
otherSig->getRequirementsWithInverses(otherReqs, otherInverses);
515+
assert(otherInverses.size() >= inverses.size()
516+
&& "otherSig's inverses are not a superset of this generic sig!");
517+
};
518+
#endif
519+
520+
// Find the requirements that aren't satisfied.
521+
for (const auto &req : reqs) {
522+
if (!otherSig->isRequirementSatisfied(req))
523+
reqs.push_back(req);
524+
}
525+
526+
}
527+
482528
bool GenericSignatureImpl::isReducedType(Type type) const {
483529
// If the type isn't canonical, it's not reduced.
484530
if (!type->isCanonical())

lib/AST/ProtocolConformance.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,43 @@ NormalProtocolConformance::getConditionalRequirements() const {
384384
{});
385385
}
386386

387+
void NormalProtocolConformance::getConditionalRequirementsWithInverses(
388+
SmallVector<Requirement, 2> &requirements,
389+
SmallVector<InverseRequirement, 2> &inverses) const {
390+
// NOTE: This is mostly the same as `ConditionalRequirementsRequest::evaluate`
391+
// and we should consider combining the two.
392+
393+
// A non-extension conformance won't have conditional requirements.
394+
const auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
395+
if (!ext) {
396+
return;
397+
}
398+
399+
// If the extension is invalid, it won't ever get a signature, so we
400+
// "succeed" with an empty result instead.
401+
if (ext->isInvalid()) {
402+
return;
403+
}
404+
405+
// A non-generic type won't have conditional requirements.
406+
const auto typeSig = ext->getExtendedNominal()->getGenericSignature();
407+
if (!typeSig) {
408+
return;
409+
}
410+
411+
const auto extensionSig = ext->getGenericSignature();
412+
413+
// The extension signature should be a superset of the type signature.
414+
assert(typeSig.getCanonicalSignature().getGenericParams() ==
415+
extensionSig.getCanonicalSignature().getGenericParams());
416+
417+
// Find the requirements in the extension that aren't proved by the original
418+
// type, these are the ones that make the conformance conditional.
419+
extensionSig.requirementsAndInversesWhenExtending(typeSig,
420+
requirements,
421+
inverses);
422+
}
423+
387424
llvm::ArrayRef<Requirement>
388425
ConditionalRequirementsRequest::evaluate(Evaluator &evaluator,
389426
NormalProtocolConformance *NPC) const {

lib/IRGen/GenProto.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,17 +2113,19 @@ namespace {
21132113
if (!normal)
21142114
return;
21152115

2116-
llvm::Optional<Requirement> scratchRequirement;
2117-
auto condReqs = normal->getConditionalRequirements();
2116+
// FIXME(kavon): probably need to emit the inverse requirements in the
2117+
// metadata so the runtime knows not to check for Copyable?
2118+
SmallVector<Requirement, 2> condReqs;
2119+
SmallVector<InverseRequirement, 2> inverses;
2120+
normal->getConditionalRequirementsWithInverses(condReqs, inverses);
21182121
if (condReqs.empty()) {
21192122
// For a protocol P that conforms to another protocol, introduce a
21202123
// conditional requirement for that P's Self: P. This aligns with
21212124
// SILWitnessTable::enumerateWitnessTableConditionalConformances().
21222125
if (auto selfProto = normal->getDeclContext()->getSelfProtocolDecl()) {
21232126
auto selfType = selfProto->getSelfInterfaceType()->getCanonicalType();
2124-
scratchRequirement.emplace(RequirementKind::Conformance, selfType,
2127+
condReqs.emplace_back(RequirementKind::Conformance, selfType,
21252128
selfProto->getDeclaredInterfaceType());
2126-
condReqs = *scratchRequirement;
21272129
}
21282130

21292131
if (condReqs.empty())

0 commit comments

Comments
 (0)