Skip to content

Commit 716ac81

Browse files
committed
AST: Cache protocol generic signature in GenericContext::getGenericSignature()
The generic signature of a protocol is simple enough that we can build it directly when asked. However, be sure to cache it for future use.
1 parent 1e27f21 commit 716ac81

File tree

4 files changed

+62
-25
lines changed

4 files changed

+62
-25
lines changed

lib/AST/Decl.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -745,13 +745,8 @@ GenericSignature *GenericContext::getGenericSignature() const {
745745

746746
// The signature of a Protocol is trivial (Self: TheProtocol) so let's compute
747747
// it.
748-
if (auto PD = dyn_cast<ProtocolDecl>(this)) {
749-
const_cast<ProtocolDecl *>(PD)->createGenericParamsIfMissing();
750-
auto self = PD->getSelfInterfaceType()->castTo<GenericTypeParamType>();
751-
auto req =
752-
Requirement(RequirementKind::Conformance, self, PD->getDeclaredType());
753-
return GenericSignature::get({self}, {req});
754-
}
748+
if (auto PD = dyn_cast<ProtocolDecl>(this))
749+
return getGenericEnvironment()->getGenericSignature();
755750

756751
return nullptr;
757752
}
@@ -765,6 +760,21 @@ GenericEnvironment *GenericContext::getGenericEnvironment() const {
765760
if (GenericSigOrEnv.dyn_cast<GenericSignature *>())
766761
return getLazyGenericEnvironmentSlow();
767762

763+
// The signature of a Protocol is trivial (Self: TheProtocol) so let's compute
764+
// it.
765+
if (auto PD = dyn_cast<ProtocolDecl>(this)) {
766+
const_cast<ProtocolDecl *>(PD)->createGenericParamsIfMissing();
767+
auto self = PD->getSelfInterfaceType()->castTo<GenericTypeParamType>();
768+
auto req =
769+
Requirement(RequirementKind::Conformance, self, PD->getDeclaredType());
770+
auto *genericSig = GenericSignature::get({self}, {req});
771+
772+
// Save it for next time.
773+
const_cast<GenericContext *>(this)
774+
->setGenericEnvironment(genericSig->createGenericEnvironment());
775+
return getGenericEnvironment();
776+
}
777+
768778
return nullptr;
769779
}
770780

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,11 @@ Type ConstraintSystem::openType(Type type, OpenedTypeMap &replacements) {
583583
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
584584
auto known = replacements.find(
585585
cast<GenericTypeParamType>(genericParam->getCanonicalType()));
586-
assert(known != replacements.end());
586+
// FIXME: This should be an assert, however protocol generic signatures
587+
// drop outer generic parameters.
588+
// assert(known != replacements.end());
589+
if (known == replacements.end())
590+
return ErrorType::get(TC.Context);
587591
return known->second;
588592
}
589593

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -754,8 +754,40 @@ GenericEnvironment *TypeChecker::checkGenericEnvironment(
754754
}
755755

756756
void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) {
757+
if (auto *proto = dyn_cast<ProtocolDecl>(typeDecl)) {
758+
// Compute the requirement signature first.
759+
if (!proto->isRequirementSignatureComputed())
760+
proto->computeRequirementSignature();
761+
762+
// The generic signature and environment is created lazily by
763+
// GenericContext::getGenericSignature(), so there is nothing we
764+
// need to do.
765+
766+
// Debugging of the generic signature builder and generic signature
767+
// generation.
768+
if (Context.LangOpts.DebugGenericSignatures) {
769+
auto *sig = proto->getGenericSignature();
770+
771+
proto->printContext(llvm::errs());
772+
llvm::errs() << "\n";
773+
llvm::errs() << "Generic signature: ";
774+
sig->print(llvm::errs());
775+
llvm::errs() << "\n";
776+
llvm::errs() << "Canonical generic signature: ";
777+
sig->getCanonicalSignature()->print(llvm::errs());
778+
llvm::errs() << "\n";
779+
}
780+
781+
return;
782+
}
783+
757784
assert(!typeDecl->getGenericEnvironment());
758785

786+
// We don't go down this path for protocols; instead, the generic signature
787+
// is simple enough that GenericContext::getGenericSignature() can build it
788+
// directly.
789+
assert(!isa<ProtocolDecl>(typeDecl));
790+
759791
auto *gp = typeDecl->getGenericParams();
760792
auto *dc = typeDecl->getDeclContext();
761793

@@ -767,13 +799,6 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) {
767799

768800
gp->setDepth(typeDecl->getGenericContextDepth());
769801

770-
// For a protocol, compute the requirement signature first. It will be used
771-
// by clients of the protocol.
772-
if (auto proto = dyn_cast<ProtocolDecl>(typeDecl)) {
773-
if (!proto->isRequirementSignatureComputed())
774-
proto->computeRequirementSignature();
775-
}
776-
777802
auto *env = checkGenericEnvironment(gp, dc,
778803
dc->getGenericSignatureOfContext(),
779804
/*allowConcreteGenericParams=*/false,

lib/Sema/TypeCheckType.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,21 +3185,19 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
31853185

31863186
auto *aliasDecl = dyn_cast<TypeAliasDecl>(member);
31873187
if (aliasDecl) {
3188+
if (aliasDecl->getGenericParams()) {
3189+
return UnboundGenericType::get(
3190+
aliasDecl, baseTy,
3191+
aliasDecl->getASTContext());
3192+
}
3193+
31883194
// FIXME: If this is a protocol typealias and we haven't built the
31893195
// protocol's generic environment yet, do so now, to ensure the
31903196
// typealias's underlying type has fully resolved dependent
31913197
// member types.
31923198
if (auto *protoDecl = dyn_cast<ProtocolDecl>(aliasDecl->getDeclContext())) {
3193-
if (protoDecl->getGenericEnvironment() == nullptr) {
3194-
ASTContext &ctx = protoDecl->getASTContext();
3195-
ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl);
3196-
}
3197-
}
3198-
3199-
if (aliasDecl->getGenericParams()) {
3200-
return UnboundGenericType::get(
3201-
aliasDecl, baseTy,
3202-
aliasDecl->getASTContext());
3199+
ASTContext &ctx = protoDecl->getASTContext();
3200+
ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl);
32033201
}
32043202
}
32053203

0 commit comments

Comments
 (0)