Skip to content

Commit 97f2f8b

Browse files
authored
Merge pull request #10711 from DougGregor/requirement-signature-improvements
2 parents 04bc382 + 5bacc08 commit 97f2f8b

18 files changed

+103
-92
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,7 +3501,7 @@ class ProtocolDecl : public NominalTypeDecl {
35013501

35023502
/// The generic signature representing exactly the new requirements introduced
35033503
/// by this protocol.
3504-
GenericSignature *RequirementSignature = nullptr;
3504+
const Requirement *RequirementSignature = nullptr;
35053505

35063506
/// True if the protocol has requirements that cannot be satisfied (e.g.
35073507
/// because they could not be imported from Objective-C).
@@ -3511,6 +3511,9 @@ class ProtocolDecl : public NominalTypeDecl {
35113511
/// value, plus one. Otherwise, it will be 0.
35123512
unsigned KnownProtocol : 6;
35133513

3514+
/// The number of requirements in the requirement signature.
3515+
unsigned NumRequirementsInSignature : 16;
3516+
35143517
bool requiresClassSlow();
35153518

35163519
bool existentialConformsToSelfSlow();
@@ -3687,8 +3690,6 @@ class ProtocolDecl : public NominalTypeDecl {
36873690

36883691
/// Create the implicit generic parameter list for a protocol or
36893692
/// extension thereof.
3690-
///
3691-
/// FIXME: protocol extensions will introduce a where clause here as well.
36923693
GenericParamList *createGenericParams(DeclContext *dc);
36933694

36943695
/// Create the generic parameters of this protocol if the haven't been
@@ -3700,17 +3701,17 @@ class ProtocolDecl : public NominalTypeDecl {
37003701
return TrailingWhere;
37013702
}
37023703

3703-
/// Retrieve the generic signature representing the requirements introduced by
3704-
/// this protocol.
3704+
/// Retrieve the requirements that describe this protocol.
37053705
///
3706-
/// These are the requirements like any inherited protocols and conformances
3707-
/// for associated types that are mentioned literally in this
3708-
/// decl. Requirements implied via inheritance are not mentioned, nor is the
3709-
/// conformance of Self to this protocol.
3710-
GenericSignature *getRequirementSignature() const {
3711-
assert(RequirementSignature &&
3706+
/// These are the requirements including any inherited protocols
3707+
/// and conformances for associated types that are introduced in this
3708+
/// protocol. Requirements implied via any other protocol (e.g., inherited
3709+
/// protocols of the inherited protocols) are not mentioned. The conformance
3710+
/// requirements listed here become entries in the witness table.
3711+
ArrayRef<Requirement> getRequirementSignature() const {
3712+
assert(isRequirementSignatureComputed() &&
37123713
"getting requirement signature before computing it");
3713-
return RequirementSignature;
3714+
return llvm::makeArrayRef(RequirementSignature, NumRequirementsInSignature);
37143715
}
37153716

37163717
/// Has the requirement signature been computed yet?
@@ -3720,9 +3721,7 @@ class ProtocolDecl : public NominalTypeDecl {
37203721

37213722
void computeRequirementSignature();
37223723

3723-
void setRequirementSignature(GenericSignature *sig) {
3724-
RequirementSignature = sig;
3725-
}
3724+
void setRequirementSignature(ArrayRef<Requirement> requirements);
37263725

37273726
// Implement isa/cast/dyncast/etc.
37283727
static bool classof(const Decl *D) {

include/swift/IRGen/Linking.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class LinkEntity {
312312
CanType associatedType,
313313
ProtocolDecl *requirement) {
314314
unsigned index = 0;
315-
for (auto &reqt : conformance->getProtocol()->getRequirementSignature()
316-
->getRequirements()) {
315+
for (const auto &reqt :
316+
conformance->getProtocol()->getRequirementSignature()) {
317317
if (reqt.getKind() == RequirementKind::Conformance &&
318318
reqt.getFirstType()->getCanonicalType() == associatedType &&
319319
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
@@ -328,9 +328,7 @@ class LinkEntity {
328328
static std::pair<CanType, ProtocolDecl*>
329329
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
330330
unsigned index) {
331-
auto &reqt =
332-
conformance->getProtocol()->getRequirementSignature()
333-
->getRequirements()[index];
331+
auto &reqt = conformance->getProtocol()->getRequirementSignature()[index];
334332
assert(reqt.getKind() == RequirementKind::Conformance);
335333
return { reqt.getFirstType()->getCanonicalType(),
336334
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };

include/swift/SIL/SILWitnessVisitor.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
6464
}
6565
};
6666

67-
for (auto &reqt : protocol->getRequirementSignature()
68-
->getCanonicalSignature()->getRequirements()) {
67+
for (const auto &reqt : protocol->getRequirementSignature()) {
6968
switch (reqt.getKind()) {
7069
// These requirements don't show up in the witness table.
7170
case RequirementKind::Superclass:
@@ -74,10 +73,11 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
7473
continue;
7574

7675
case RequirementKind::Conformance: {
77-
auto type = CanType(reqt.getFirstType());
76+
auto type = reqt.getFirstType()->getCanonicalType();
7877
assert(type->isTypeParameter());
7978
auto requirement =
80-
cast<ProtocolType>(CanType(reqt.getSecondType()))->getDecl();
79+
cast<ProtocolType>(reqt.getSecondType()->getCanonicalType())
80+
->getDecl();
8181

8282
// ObjC protocols do not have witnesses.
8383
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(requirement))

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,9 @@ namespace {
676676

677677
OS << " requirement signature=";
678678
if (PD->isRequirementSignatureComputed()) {
679-
OS << PD->getRequirementSignature()->getAsString();
679+
OS << GenericSignature::get({PD->getProtocolSelfType()} ,
680+
PD->getRequirementSignature())
681+
->getAsString();
680682
} else {
681683
OS << "<null>";
682684
}

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,9 @@ void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
13671367
if (isa<AssociatedTypeDecl>(attachingTo))
13681368
flags |= SwapSelfAndDependentMemberType;
13691369
printGenericSignature(
1370-
proto->getRequirementSignature(), flags,
1370+
GenericSignature::get({proto->getProtocolSelfType()} ,
1371+
proto->getRequirementSignature()),
1372+
flags,
13711373
[&](const Requirement &req) {
13721374
auto location = bestRequirementPrintLocation(proto, req);
13731375
return location.AttachedTo == attachingTo && location.InWhereClause;

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2348,7 +2348,7 @@ class Verifier : public ASTWalker {
23482348
if (!normal->isInvalid()){
23492349
auto conformances = normal->getSignatureConformances();
23502350
unsigned idx = 0;
2351-
for (auto req : proto->getRequirementSignature()->getRequirements()) {
2351+
for (const auto &req : proto->getRequirementSignature()) {
23522352
if (req.getKind() != RequirementKind::Conformance)
23532353
continue;
23542354

lib/AST/Decl.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,10 +2861,11 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
28612861
ProtocolDeclBits.RequiresClass = false;
28622862
ProtocolDeclBits.ExistentialConformsToSelfValid = false;
28632863
ProtocolDeclBits.ExistentialConformsToSelf = false;
2864-
KnownProtocol = 0;
28652864
ProtocolDeclBits.Circularity
28662865
= static_cast<unsigned>(CircularityCheck::Unchecked);
28672866
HasMissingRequirements = false;
2867+
KnownProtocol = 0;
2868+
NumRequirementsInSignature = 0;
28682869
}
28692870

28702871
llvm::TinyPtrVector<ProtocolDecl *>
@@ -2895,7 +2896,7 @@ ProtocolDecl::getInheritedProtocols() const {
28952896

28962897
// Gather inherited protocols from the requirement signature.
28972898
auto selfType = getProtocolSelfType();
2898-
for (auto req : getRequirementSignature()->getRequirements()) {
2899+
for (const auto &req : getRequirementSignature()) {
28992900
if (req.getKind() == RequirementKind::Conformance &&
29002901
req.getFirstType()->isEqual(selfType))
29012902
result.push_back(req.getSecondType()->castTo<ProtocolType>()->getDecl());
@@ -3299,8 +3300,23 @@ void ProtocolDecl::computeRequirementSignature() {
32993300
GenericSignatureBuilder::RequirementSource
33003301
::forRequirementSignature(selfPA, this),
33013302
nullptr);
3302-
3303-
RequirementSignature = builder.computeGenericSignature(SourceLoc());
3303+
3304+
// Compute and record the signature.
3305+
auto requirementSig = builder.computeGenericSignature(SourceLoc());
3306+
RequirementSignature = requirementSig->getRequirements().data();
3307+
assert(RequirementSignature != nullptr);
3308+
NumRequirementsInSignature = requirementSig->getRequirements().size();
3309+
}
3310+
3311+
void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
3312+
assert(!RequirementSignature && "already computed requirement signature");
3313+
if (requirements.empty()) {
3314+
RequirementSignature = reinterpret_cast<Requirement *>(this + 1);
3315+
NumRequirementsInSignature = 0;
3316+
} else {
3317+
RequirementSignature = getASTContext().AllocateCopy(requirements).data();
3318+
NumRequirementsInSignature = requirements.size();
3319+
}
33043320
}
33053321

33063322
/// Returns the default witness for a requirement, or nullptr if there is

lib/AST/DeclContext.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,6 @@ ProtocolDecl *DeclContext::getAsProtocolExtensionContext() const {
105105
GenericTypeParamType *DeclContext::getProtocolSelfType() const {
106106
assert(getAsProtocolOrProtocolExtensionContext() && "not a protocol");
107107

108-
// FIXME: This comes up when the extension didn't resolve,
109-
// and we have a protocol nested inside that extension
110-
// (which is not allowed in the first place).
111-
//
112-
// Handle this more systematically elsewhere.
113-
if (!isInnermostContextGeneric())
114-
return nullptr;
115-
116108
return getGenericParamsOfContext()->getParams().front()
117109
->getDeclaredInterfaceType()
118110
->castTo<GenericTypeParamType>();

lib/AST/GenericSignature.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -793,13 +793,13 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
793793

794794
#ifndef NDEBUG
795795
// Local function to determine whether there is a conformance of the given
796-
// subject type to the given protocol within the given generic signature's
797-
// explicit requirements.
798-
auto hasConformanceInSignature = [&](const GenericSignature *genericSig,
796+
// subject type to the given protocol within the given set of explicit
797+
// requirements.
798+
auto hasConformanceInSignature = [&](ArrayRef<Requirement> requirements,
799799
Type subjectType,
800800
ProtocolDecl *proto) -> bool {
801801
// Make sure this requirement exists in the requirement signature.
802-
for (const auto& req: genericSig->getRequirements()) {
802+
for (const auto& req: requirements) {
803803
if (req.getKind() == RequirementKind::Conformance &&
804804
req.getFirstType()->isEqual(subjectType) &&
805805
req.getSecondType()->castTo<ProtocolType>()->getDecl()
@@ -814,16 +814,27 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
814814

815815
// Local function to construct the conformance access path from the
816816
// requirement.
817-
std::function<void(GenericSignature *, const RequirementSource *,
818-
ProtocolDecl *, Type)> buildPath;
819-
buildPath = [&](GenericSignature *sig, const RequirementSource *source,
820-
ProtocolDecl *conformingProto, Type rootType) {
817+
std::function<void(ArrayRef<Requirement>, const RequirementSource *,
818+
ProtocolDecl *, Type, ProtocolDecl *)> buildPath;
819+
buildPath = [&](ArrayRef<Requirement> reqs, const RequirementSource *source,
820+
ProtocolDecl *conformingProto, Type rootType,
821+
ProtocolDecl *requirementSignatureProto) {
821822
// Each protocol requirement is a step along the path.
822823
if (source->isProtocolRequirement()) {
824+
// If we're expanding for a protocol that has no requirement signature
825+
// (yet) and have hit the penultimate step, this is the last step
826+
// that would occur in the requirement signature.
827+
if (!source->parent->parent && requirementSignatureProto) {
828+
Type subjectType = source->getStoredType()->getCanonicalType();
829+
path.path.push_back({subjectType, conformingProto});
830+
return;
831+
}
832+
823833
// Follow the rest of the path to derive the conformance into which
824834
// this particular protocol requirement step would look.
825835
auto inProtocol = source->getProtocolDecl();
826-
buildPath(sig, source->parent, inProtocol, rootType);
836+
buildPath(reqs, source->parent, inProtocol, rootType,
837+
requirementSignatureProto);
827838
assert(path.path.back().second == inProtocol &&
828839
"path produces incorrect conformance");
829840

@@ -857,11 +868,10 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
857868
"missing signature");
858869
}
859870

860-
// Get a generic signature builder for the requirement signature. This has
861-
// the requirement we need.
862-
auto reqSig = inProtocol->getRequirementSignature();
863-
auto &reqSigBuilder = *reqSig->getGenericSignatureBuilder(
864-
*inProtocol->getModuleContext());
871+
// Get a generic signature for the protocol's signature.
872+
auto inProtoSig = inProtocol->getGenericSignature();
873+
auto &inProtoSigBuilder = *inProtoSig->getGenericSignatureBuilder(
874+
*inProtocol->getModuleContext());
865875

866876
// Retrieve the stored type, but erase all of the specific associated
867877
// type declarations; we don't want any details of the enclosing context
@@ -870,9 +880,9 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
870880

871881
// Dig out the potential archetype for this stored type.
872882
auto pa =
873-
reqSigBuilder.resolveArchetype(
883+
inProtoSigBuilder.resolveArchetype(
874884
storedType,
875-
ArchetypeResolutionKind::AlwaysPartial);
885+
ArchetypeResolutionKind::WellFormed);
876886
auto equivClass = pa->getOrCreateEquivalenceClass();
877887

878888
// Find the conformance of this potential archetype to the protocol in
@@ -881,8 +891,8 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
881891
assert(conforms != equivClass->conformsTo.end());
882892

883893
// Compute the root type, canonicalizing it w.r.t. the protocol context.
884-
auto inProtoSig = inProtocol->getGenericSignature();
885894
auto conformsSource = getBestRequirementSource(conforms->second);
895+
assert(conformsSource != source || !requirementSignatureProto);
886896
Type localRootType = conformsSource->getRootPotentialArchetype()
887897
->getDependentType(inProtoSig->getGenericParams(),
888898
/*allowUnresolved*/true);
@@ -891,15 +901,17 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
891901
*inProtocol->getModuleContext());
892902

893903
// Build the path according to the requirement signature.
894-
buildPath(reqSig, conformsSource, conformingProto, localRootType);
904+
buildPath(inProtocol->getRequirementSignature(), conformsSource,
905+
conformingProto, localRootType, inProtocol);
895906

896907
// We're done.
897908
return;
898909
}
899910

900911
// If we still have a parent, keep going.
901912
if (source->parent) {
902-
buildPath(sig, source->parent, conformingProto, rootType);
913+
buildPath(reqs, source->parent, conformingProto, rootType,
914+
requirementSignatureProto);
903915
return;
904916
}
905917

@@ -914,7 +926,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
914926
rootType->isEqual(conformingProto->getSelfInterfaceType()))
915927
return;
916928

917-
assert(hasConformanceInSignature(sig, rootType, conformingProto) &&
929+
assert(hasConformanceInSignature(reqs, rootType, conformingProto) &&
918930
"missing explicit conformance in signature");
919931

920932
// Add the root of the path, which starts at this explicit requirement.
@@ -929,7 +941,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
929941
/*allowUnresolved=*/false);
930942

931943
// Build the path.
932-
buildPath(this, source, protocol, rootType);
944+
buildPath(getRequirements(), source, protocol, rootType, nullptr);
933945

934946
// Return the path; we're done!
935947
return path;

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2628,12 +2628,10 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
26282628
// cannot compute the requirement signature directly, because that may be
26292629
// infinitely recursive: this code is also used to construct it.
26302630
if (Proto->isRequirementSignatureComputed()) {
2631-
auto reqSig = Proto->getRequirementSignature();
2632-
26332631
auto innerSource =
26342632
FloatingRequirementSource::viaProtocolRequirement(Source, Proto,
26352633
/*inferred=*/false);
2636-
for (auto req : reqSig->getRequirements()) {
2634+
for (const auto &req : Proto->getRequirementSignature()) {
26372635
auto reqResult = addRequirement(req, innerSource, nullptr,
26382636
&protocolSubMap);
26392637
if (isErrorResult(reqResult)) return reqResult;

lib/AST/ProtocolConformance.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ void NormalProtocolConformance::setSignatureConformances(
311311

312312
#if !NDEBUG
313313
unsigned idx = 0;
314-
for (auto req : getProtocol()->getRequirementSignature()->getRequirements()) {
314+
for (const auto &req : getProtocol()->getRequirementSignature()) {
315315
if (req.getKind() == RequirementKind::Conformance) {
316316
assert(idx < conformances.size());
317317
assert(conformances[idx].getRequirement() ==
@@ -596,8 +596,7 @@ NormalProtocolConformance::getAssociatedConformance(Type assocType,
596596
"signature conformances not yet computed");
597597

598598
unsigned conformanceIndex = 0;
599-
for (auto &reqt :
600-
getProtocol()->getRequirementSignature()->getRequirements()) {
599+
for (const auto &reqt : getProtocol()->getRequirementSignature()) {
601600
if (reqt.getKind() == RequirementKind::Conformance) {
602601
// Is this the conformance we're looking for?
603602
if (reqt.getFirstType()->isEqual(assocType) &&

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,13 +4159,13 @@ namespace {
41594159
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
41604160
result->setCheckedInheritanceClause();
41614161

4162-
auto *env = Impl.buildGenericEnvironment(result->getGenericParams(), dc);
4163-
result->setGenericEnvironment(env);
4164-
41654162
// Compute the requirement signature.
41664163
if (!result->isRequirementSignatureComputed())
41674164
result->computeRequirementSignature();
41684165

4166+
auto *env = Impl.buildGenericEnvironment(result->getGenericParams(), dc);
4167+
result->setGenericEnvironment(env);
4168+
41694169
result->setMemberLoader(&Impl, 0);
41704170

41714171
// Add the protocol decl to ExternalDefinitions so that IRGen can emit
@@ -7376,7 +7376,7 @@ void ClangImporter::Implementation::finishProtocolConformance(
73767376

73777377
// Collect conformances for the requirement signature.
73787378
SmallVector<ProtocolConformanceRef, 4> reqConformances;
7379-
for (auto req : proto->getRequirementSignature()->getRequirements()) {
7379+
for (const auto &req : proto->getRequirementSignature()) {
73807380
if (req.getKind() != RequirementKind::Conformance)
73817381
continue;
73827382

0 commit comments

Comments
 (0)