Skip to content

Protocol generic signature cleanup #21730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,13 +745,8 @@ GenericSignature *GenericContext::getGenericSignature() const {

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

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

// The signature of a Protocol is trivial (Self: TheProtocol) so let's compute
// it.
if (auto PD = dyn_cast<ProtocolDecl>(this)) {
const_cast<ProtocolDecl *>(PD)->createGenericParamsIfMissing();
auto self = PD->getSelfInterfaceType()->castTo<GenericTypeParamType>();
auto req =
Requirement(RequirementKind::Conformance, self, PD->getDeclaredType());
auto *genericSig = GenericSignature::get({self}, {req});

// Save it for next time.
const_cast<GenericContext *>(this)
->setGenericEnvironment(genericSig->createGenericEnvironment());
return getGenericEnvironment();
}

return nullptr;
}

Expand Down
3 changes: 0 additions & 3 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4407,9 +4407,6 @@ namespace {
if (!result->isRequirementSignatureComputed())
result->computeRequirementSignature();

auto *env = Impl.buildGenericEnvironment(result->getGenericParams(), dc);
result->setGenericEnvironment(env);

result->setMemberLoader(&Impl, 0);

// Add the protocol decl to ExternalDefinitions so that IRGen can emit
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3704,6 +3704,7 @@ bool swift::isExtensionApplied(DeclContext &DC, Type BaseTy,
return true;

TypeChecker *TC = &createTypeChecker(DC.getASTContext());
TC->validateExtension(const_cast<ExtensionDecl *>(ED));

ConstraintSystemOptions Options;
ConstraintSystem CS(*TC, &DC, Options);
Expand Down
6 changes: 5 additions & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,11 @@ Type ConstraintSystem::openType(Type type, OpenedTypeMap &replacements) {
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
auto known = replacements.find(
cast<GenericTypeParamType>(genericParam->getCanonicalType()));
assert(known != replacements.end());
// FIXME: This should be an assert, however protocol generic signatures
// drop outer generic parameters.
// assert(known != replacements.end());
if (known == replacements.end())
return ErrorType::get(TC.Context);
return known->second;
}

Expand Down
10 changes: 1 addition & 9 deletions lib/Sema/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,10 @@ static void doGlobalExtensionLookup(Type BaseType,
extension))
continue;

bool validatedExtension = false;
for (auto Member : extension->getMembers()) {
if (auto VD = dyn_cast<ValueDecl>(Member))
if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver)) {
// Resolve the extension, if we haven't done so already.
if (!validatedExtension && TypeResolver) {
TypeResolver->resolveExtension(extension);
validatedExtension = true;
}

if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver))
FoundDecls.push_back(VD);
}
}
}

Expand Down
7 changes: 0 additions & 7 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4193,13 +4193,6 @@ void TypeChecker::validateDeclForNameLookup(ValueDecl *D) {
return;
proto->computeType();

auto *gp = proto->getGenericParams();
gp->setDepth(proto->getGenericContextDepth());

for (auto ATD : proto->getAssociatedTypeMembers()) {
validateDeclForNameLookup(ATD);
}

// Compute the requirement signature later to avoid circularity.
DelayedRequirementSignatures.insert(proto);

Expand Down
39 changes: 32 additions & 7 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,40 @@ GenericEnvironment *TypeChecker::checkGenericEnvironment(
}

void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) {
if (auto *proto = dyn_cast<ProtocolDecl>(typeDecl)) {
// Compute the requirement signature first.
if (!proto->isRequirementSignatureComputed())
proto->computeRequirementSignature();

// The generic signature and environment is created lazily by
// GenericContext::getGenericSignature(), so there is nothing we
// need to do.

// Debugging of the generic signature builder and generic signature
// generation.
if (Context.LangOpts.DebugGenericSignatures) {
auto *sig = proto->getGenericSignature();

proto->printContext(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Canonical generic signature: ";
sig->getCanonicalSignature()->print(llvm::errs());
llvm::errs() << "\n";
}

return;
}

assert(!typeDecl->getGenericEnvironment());

// We don't go down this path for protocols; instead, the generic signature
// is simple enough that GenericContext::getGenericSignature() can build it
// directly.
assert(!isa<ProtocolDecl>(typeDecl));

auto *gp = typeDecl->getGenericParams();
auto *dc = typeDecl->getDeclContext();

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

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

// For a protocol, compute the requirement signature first. It will be used
// by clients of the protocol.
if (auto proto = dyn_cast<ProtocolDecl>(typeDecl)) {
if (!proto->isRequirementSignatureComputed())
proto->computeRequirementSignature();
}

auto *env = checkGenericEnvironment(gp, dc,
dc->getGenericSignatureOfContext(),
/*allowConcreteGenericParams=*/false,
Expand Down
18 changes: 8 additions & 10 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3185,21 +3185,19 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,

auto *aliasDecl = dyn_cast<TypeAliasDecl>(member);
if (aliasDecl) {
if (aliasDecl->getGenericParams()) {
return UnboundGenericType::get(
aliasDecl, baseTy,
aliasDecl->getASTContext());
}

// FIXME: If this is a protocol typealias and we haven't built the
// protocol's generic environment yet, do so now, to ensure the
// typealias's underlying type has fully resolved dependent
// member types.
if (auto *protoDecl = dyn_cast<ProtocolDecl>(aliasDecl->getDeclContext())) {
if (protoDecl->getGenericEnvironment() == nullptr) {
ASTContext &ctx = protoDecl->getASTContext();
ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl);
}
}

if (aliasDecl->getGenericParams()) {
return UnboundGenericType::get(
aliasDecl, baseTy,
aliasDecl->getASTContext());
ASTContext &ctx = protoDecl->getASTContext();
ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl);
}
}

Expand Down