Skip to content

Commit e659ecf

Browse files
Merge pull request #31214 from AnthonyLatsis/req-sat-by-fast
AST: Add fast path for matching can. signatures in requirementsNotSatisfiedBy
2 parents ec465e1 + ba26d57 commit e659ecf

File tree

3 files changed

+30
-35
lines changed

3 files changed

+30
-35
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
366366
/// \param otherSig Another generic signature whose generic parameters are
367367
/// equivalent to or a subset of the generic parameters in this signature.
368368
SmallVector<Requirement, 4> requirementsNotSatisfiedBy(
369-
GenericSignature otherSig);
369+
GenericSignature otherSig) const;
370370

371371
/// Return the canonical version of the given type under this generic
372372
/// signature.

lib/AST/GenericSignature.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,19 +592,23 @@ bool GenericSignatureImpl::isRequirementSatisfied(Requirement requirement) {
592592
}
593593

594594
SmallVector<Requirement, 4> GenericSignatureImpl::requirementsNotSatisfiedBy(
595-
GenericSignature otherSig) {
595+
GenericSignature otherSig) const {
596596
SmallVector<Requirement, 4> result;
597597

598-
// If the signatures are the same, all requirements are satisfied.
598+
// If the signatures match by pointer, all requirements are satisfied.
599599
if (otherSig.getPointer() == this) return result;
600600

601601
// If there is no other signature, no requirements are satisfied.
602602
if (!otherSig){
603-
result.insert(result.end(),
604-
getRequirements().begin(), getRequirements().end());
603+
const auto reqs = getRequirements();
604+
result.append(reqs.begin(), reqs.end());
605605
return result;
606606
}
607607

608+
// If the canonical signatures are equal, all requirements are satisfied.
609+
if (getCanonicalSignature() == otherSig->getCanonicalSignature())
610+
return result;
611+
608612
// Find the requirements that aren't satisfied.
609613
for (const auto &req : getRequirements()) {
610614
if (!otherSig->isRequirementSatisfied(req))

lib/AST/ProtocolConformance.cpp

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements()
501501
};
502502

503503
CRState = ConditionalRequirementsState::Computing;
504-
auto success = [this](ArrayRef<Requirement> reqs) {
504+
auto success = [this](ArrayRef<Requirement> reqs = {}) {
505505
ConditionalRequirements = reqs;
506506
assert(CRState == ConditionalRequirementsState::Computing);
507507
CRState = ConditionalRequirementsState::Complete;
@@ -510,30 +510,23 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements()
510510
assert(CRState == ConditionalRequirementsState::Computing);
511511
CRState = ConditionalRequirementsState::Uncomputed;
512512
};
513-
514-
auto &ctxt = getProtocol()->getASTContext();
515-
auto DC = getDeclContext();
516-
// A non-extension conformance won't have conditional requirements.
517-
if (!isa<ExtensionDecl>(DC)) {
518-
success({});
519-
return;
520-
}
521513

522-
auto *ext = cast<ExtensionDecl>(DC);
523-
auto nominal = ext->getExtendedNominal();
524-
auto typeSig = nominal->getGenericSignature();
525-
526-
// A non-generic type won't have conditional requirements.
527-
if (!typeSig) {
528-
success({});
529-
return;
514+
// A non-extension conformance won't have conditional requirements.
515+
const auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
516+
if (!ext) {
517+
return success();
530518
}
531519

532520
// If the extension is invalid, it won't ever get a signature, so we
533521
// "succeed" with an empty result instead.
534522
if (ext->isInvalid()) {
535-
success({});
536-
return;
523+
return success();
524+
}
525+
526+
// A non-generic type won't have conditional requirements.
527+
const auto typeSig = ext->getExtendedNominal()->getGenericSignature();
528+
if (!typeSig) {
529+
return success();
537530
}
538531

539532
// Recursively validating the signature comes up frequently as expanding
@@ -542,28 +535,26 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements()
542535
//
543536
// FIXME: In the long run, break this cycle in a more principled way.
544537
if (ext->isComputingGenericSignature()) {
545-
failure();
546-
return;
538+
return failure();
547539
}
548540

549-
auto extensionSig = ext->getGenericSignature();
550-
auto canExtensionSig = extensionSig.getCanonicalSignature();
551-
auto canTypeSig = typeSig.getCanonicalSignature();
552-
if (canTypeSig == canExtensionSig) {
553-
success({});
554-
return;
555-
}
541+
const auto extensionSig = ext->getGenericSignature();
556542

557543
// The extension signature should be a superset of the type signature, meaning
558544
// every thing in the type signature either is included too or is implied by
559545
// something else. The most important bit is having the same type
560546
// parameters. (NB. if/when Swift gets parameterized extensions, this needs to
561547
// change.)
562-
assert(canTypeSig.getGenericParams() == canExtensionSig.getGenericParams());
548+
assert(typeSig->getCanonicalSignature().getGenericParams() ==
549+
extensionSig->getCanonicalSignature().getGenericParams());
563550

564551
// Find the requirements in the extension that aren't proved by the original
565552
// type, these are the ones that make the conformance conditional.
566-
success(ctxt.AllocateCopy(extensionSig->requirementsNotSatisfiedBy(typeSig)));
553+
const auto unsatReqs = extensionSig->requirementsNotSatisfiedBy(typeSig);
554+
if (unsatReqs.empty())
555+
return success();
556+
557+
return success(getProtocol()->getASTContext().AllocateCopy(unsatReqs));
567558
}
568559

569560
void NormalProtocolConformance::setSignatureConformances(

0 commit comments

Comments
 (0)