From fe16cf869d65cd20fca7ce5666350b07e838bf91 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 19 Feb 2017 01:48:27 -0800 Subject: [PATCH 1/4] Sema: Move some code around for better organization --- lib/Sema/TypeCheckGeneric.cpp | 274 +++++++++++++++++---------------- lib/Sema/TypeCheckProtocol.cpp | 13 ++ 2 files changed, 158 insertions(+), 129 deletions(-) diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 48de78454e54b..474fea61eb795 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -23,6 +23,10 @@ using namespace swift; +/// +/// GenericTypeResolver implementations +/// + Type DependentGenericTypeResolver::resolveGenericTypeParamType( GenericTypeParamType *gp) { assert(gp->getDecl() && "Missing generic parameter declaration"); @@ -230,6 +234,10 @@ CompleteGenericTypeResolver::recordParamType(ParamDecl *decl, Type type) { decl->setInterfaceType(type); } +/// +/// Common code for generic functions, generic types +/// + /// Check the generic parameters in the given generic parameter list (and its /// parent generic parameter lists) according to the given resolver. void TypeChecker::checkGenericParamList(GenericSignatureBuilder *builder, @@ -355,6 +363,86 @@ void TypeChecker::checkGenericParamList(GenericSignatureBuilder *builder, } } +void +TypeChecker::prepareGenericParamList(GenericParamList *gp, + DeclContext *dc) { + Accessibility access; + if (auto *fd = dyn_cast(dc)) + access = fd->getFormalAccess(); + else if (auto *nominal = dyn_cast(dc)) + access = nominal->getFormalAccess(); + else + access = Accessibility::Internal; + access = std::max(access, Accessibility::Internal); + + unsigned depth = gp->getDepth(); + for (auto paramDecl : *gp) { + paramDecl->setDepth(depth); + if (!paramDecl->hasAccessibility()) + paramDecl->setAccessibility(access); + } +} + +/// Add the generic parameter types from the given list to the vector. +static void addGenericParamTypes(GenericParamList *gpList, + SmallVectorImpl ¶ms) { + if (!gpList) return; + + for (auto gpDecl : *gpList) { + params.push_back( + gpDecl->getDeclaredInterfaceType()->castTo()); + } +} + +static void revertDependentTypeLoc(TypeLoc &tl) { + // If there's no type representation, there's nothing to revert. + if (!tl.getTypeRepr()) + return; + + // Don't revert an error type; we've already complained. + if (tl.wasValidated() && tl.isError()) + return; + + // Make sure we validate the type again. + tl.setType(Type(), /*validated=*/false); +} + +/// Revert the dependent types within the given generic parameter list. +void TypeChecker::revertGenericParamList(GenericParamList *genericParams) { + // Revert the inherited clause of the generic parameter list. + for (auto param : *genericParams) { + param->setCheckedInheritanceClause(false); + for (auto &inherited : param->getInherited()) + revertDependentTypeLoc(inherited); + } + + // Revert the requirements of the generic parameter list. + for (auto &req : genericParams->getRequirements()) { + if (req.isInvalid()) + continue; + + switch (req.getKind()) { + case RequirementReprKind::TypeConstraint: { + revertDependentTypeLoc(req.getSubjectLoc()); + revertDependentTypeLoc(req.getConstraintLoc()); + break; + } + case RequirementReprKind::LayoutConstraint: { + revertDependentTypeLoc(req.getSubjectLoc()); + break; + } + case RequirementReprKind::SameType: + revertDependentTypeLoc(req.getFirstTypeLoc()); + revertDependentTypeLoc(req.getSecondTypeLoc()); + break; + } + } +} + +/// +/// Generic functions +/// + /// Check the signature of a generic function. static bool checkGenericFuncSignature(TypeChecker &tc, GenericSignatureBuilder *builder, @@ -409,6 +497,20 @@ static bool checkGenericFuncSignature(TypeChecker &tc, return badType; } +void TypeChecker::revertGenericFuncSignature(AbstractFunctionDecl *func) { + // Revert the result type. + if (auto fn = dyn_cast(func)) + if (!fn->getBodyResultTypeLoc().isNull()) + revertDependentTypeLoc(fn->getBodyResultTypeLoc()); + + // Revert the body parameter types. + for (auto paramList : func->getParameterLists()) { + for (auto ¶m : *paramList) { + revertDependentTypeLoc(param->getTypeLoc()); + } + } +} + /// Determine whether the given type is \c Self, an associated type of \c Self, /// or a concrete type. static bool isSelfDerivedOrConcrete(Type protoSelf, Type type) { @@ -427,35 +529,43 @@ static bool isSelfDerivedOrConcrete(Type protoSelf, Type type) { return false; } -void -TypeChecker::prepareGenericParamList(GenericParamList *gp, - DeclContext *dc) { - Accessibility access; - if (auto *fd = dyn_cast(dc)) - access = fd->getFormalAccess(); - else if (auto *nominal = dyn_cast(dc)) - access = nominal->getFormalAccess(); - else - access = Accessibility::Internal; - access = std::max(access, Accessibility::Internal); - - unsigned depth = gp->getDepth(); - for (auto paramDecl : *gp) { - paramDecl->setDepth(depth); - if (!paramDecl->hasAccessibility()) - paramDecl->setAccessibility(access); - } -} +// For a generic requirement in a protocol, make sure that the requirement +// set didn't add any requirements to Self or its associated types. +static bool checkProtocolSelfRequirements(GenericSignature *sig, + ValueDecl *decl, + TypeChecker &TC) { + // For a generic requirement in a protocol, make sure that the requirement + // set didn't add any requirements to Self or its associated types. + if (auto *proto = dyn_cast(decl->getDeclContext())) { + auto protoSelf = proto->getSelfInterfaceType(); + for (auto req : sig->getRequirements()) { + // If one of the types in the requirement is dependent on a non-Self + // type parameter, this requirement is okay. + if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) || + !isSelfDerivedOrConcrete(protoSelf, req.getSecondType())) + continue; -/// Add the generic parameter types from the given list to the vector. -static void addGenericParamTypes(GenericParamList *gpList, - SmallVectorImpl ¶ms) { - if (!gpList) return; + // The conformance of 'Self' to the protocol is okay. + if (req.getKind() == RequirementKind::Conformance && + req.getSecondType()->getAs()->getDecl() == proto && + req.getFirstType()->is()) + continue; - for (auto gpDecl : *gpList) { - params.push_back( - gpDecl->getDeclaredInterfaceType()->castTo()); + TC.diagnose(decl, + TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4 + ? diag::requirement_restricts_self + : diag::requirement_restricts_self_swift3, + decl->getDescriptiveKind(), decl->getFullName(), + req.getFirstType().getString(), + static_cast(req.getKind()), + req.getSecondType().getString()); + + if (TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4) + return true; + } } + + return false; } GenericSignature * @@ -504,38 +614,8 @@ TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) { // the type of the generic function. auto sig = builder.getGenericSignature(); - // For a generic requirement in a protocol, make sure that the requirement - // set didn't add any requirements to Self or its associated types. - if (!invalid && func->getGenericParams() && - isa(func->getDeclContext())) { - auto proto = cast(func->getDeclContext()); - auto protoSelf = proto->getSelfInterfaceType(); - for (auto req : sig->getRequirements()) { - // If one of the types in the requirement is dependent on a non-Self - // type parameter, this requirement is okay. - if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) || - !isSelfDerivedOrConcrete(protoSelf, req.getSecondType())) - continue; - - // The conformance of 'Self' to the protocol is okay. - if (req.getKind() == RequirementKind::Conformance && - req.getSecondType()->getAs()->getDecl() == proto && - req.getFirstType()->is()) - continue; - - diagnose(func, - Context.LangOpts.EffectiveLanguageVersion[0] >= 4 - ? diag::requirement_restricts_self - : diag::requirement_restricts_self_swift3, - func->getDescriptiveKind(), func->getFullName(), - req.getFirstType().getString(), - static_cast(req.getKind()), - req.getSecondType().getString()); - - if (Context.LangOpts.EffectiveLanguageVersion[0] >= 4) - invalid = true; - } - } + if (!invalid) + invalid = checkProtocolSelfRequirements(sig, func, *this); // Debugging of the generic signature builder and generic signature generation. if (Context.LangOpts.DebugGenericSignatures) { @@ -696,6 +776,10 @@ void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func, } } +/// +/// Generic types +/// + /// Visit the given generic parameter lists from the outermost to the innermost, /// calling the visitor function for each list. static void visitOuterToInner( @@ -807,51 +891,6 @@ GenericEnvironment *TypeChecker::checkGenericEnvironment( return sig->createGenericEnvironment(*module); } -static void revertDependentTypeLoc(TypeLoc &tl) { - // If there's no type representation, there's nothing to revert. - if (!tl.getTypeRepr()) - return; - - // Don't revert an error type; we've already complained. - if (tl.wasValidated() && tl.isError()) - return; - - // Make sure we validate the type again. - tl.setType(Type(), /*validated=*/false); -} - -/// Revert the dependent types within the given generic parameter list. -void TypeChecker::revertGenericParamList(GenericParamList *genericParams) { - // Revert the inherited clause of the generic parameter list. - for (auto param : *genericParams) { - param->setCheckedInheritanceClause(false); - for (auto &inherited : param->getInherited()) - revertDependentTypeLoc(inherited); - } - - // Revert the requirements of the generic parameter list. - for (auto &req : genericParams->getRequirements()) { - if (req.isInvalid()) - continue; - - switch (req.getKind()) { - case RequirementReprKind::TypeConstraint: { - revertDependentTypeLoc(req.getSubjectLoc()); - revertDependentTypeLoc(req.getConstraintLoc()); - break; - } - case RequirementReprKind::LayoutConstraint: { - revertDependentTypeLoc(req.getSubjectLoc()); - break; - } - case RequirementReprKind::SameType: - revertDependentTypeLoc(req.getFirstTypeLoc()); - revertDependentTypeLoc(req.getSecondTypeLoc()); - break; - } - } -} - void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { auto *gp = typeDecl->getGenericParams(); auto *dc = typeDecl->getDeclContext(); @@ -871,19 +910,9 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { typeDecl->setGenericEnvironment(env); } -void TypeChecker::revertGenericFuncSignature(AbstractFunctionDecl *func) { - // Revert the result type. - if (auto fn = dyn_cast(func)) - if (!fn->getBodyResultTypeLoc().isNull()) - revertDependentTypeLoc(fn->getBodyResultTypeLoc()); - - // Revert the body parameter types. - for (auto paramList : func->getParameterLists()) { - for (auto ¶m : *paramList) { - revertDependentTypeLoc(param->getTypeLoc()); - } - } -} +/// +/// Checking bound generic type arguments +/// std::pair TypeChecker::checkGenericArguments( DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner, @@ -982,16 +1011,3 @@ std::pair TypeChecker::checkGenericArguments( return std::make_pair(false, true); } - -Type TypeChecker::getWitnessType(Type type, ProtocolDecl *protocol, - ProtocolConformanceRef conformance, - Identifier name, - Diag<> brokenProtocolDiag) { - Type ty = ProtocolConformanceRef::getTypeWitnessByName(type, conformance, - name, this); - if (!ty && - !(conformance.isConcrete() && conformance.getConcrete()->isInvalid())) - diagnose(protocol->getLoc(), brokenProtocolDiag); - - return ty; -} diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 3e6e4be83c3e7..a2b23115f9c47 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -6060,3 +6060,16 @@ void TypeChecker::recordKnownWitness(NormalProtocolConformance *conformance, conformance->setWitness(req, match.getWitness(Context, std::move(reqEnvironment))); } + +Type TypeChecker::getWitnessType(Type type, ProtocolDecl *protocol, + ProtocolConformanceRef conformance, + Identifier name, + Diag<> brokenProtocolDiag) { + Type ty = ProtocolConformanceRef::getTypeWitnessByName(type, conformance, + name, this); + if (!ty && + !(conformance.isConcrete() && conformance.getConcrete()->isInvalid())) + diagnose(protocol->getLoc(), brokenProtocolDiag); + + return ty; +} From b319a3aa322dd22b4a8a19b77edf71be0acd38d8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 19 Feb 2017 20:26:25 -0800 Subject: [PATCH 2/4] AST: Clean up some more duplication using the new GenericContext --- include/swift/AST/ASTContext.h | 23 ++++-------- include/swift/AST/LazyResolver.h | 15 +++----- include/swift/Serialization/ModuleFile.h | 5 ++- lib/AST/ASTContext.cpp | 45 ++++++++---------------- lib/AST/Decl.cpp | 45 ++++-------------------- lib/Serialization/Deserialization.cpp | 29 +++------------ 6 files changed, 39 insertions(+), 123 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 718ea16bc542b..8bcdfa75bab7a 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -58,13 +58,13 @@ namespace swift { class ExtensionDecl; class ForeignRepresentationInfo; class FuncDecl; + class GenericContext; class InFlightDiagnostic; class IterableDeclContext; - class LazyAbstractFunctionData; - class LazyGenericTypeData; class LazyContextData; - class LazyMemberLoader; + class LazyGenericContextData; class LazyIterableDeclContextData; + class LazyMemberLoader; class LazyResolver; class PatternBindingDecl; class PatternBindingInitializer; @@ -722,25 +722,16 @@ class ASTContext { /// \param lazyLoader If non-null, the lazy loader to use when creating the /// lazy data. The pointer must either be null or be consistent /// across all calls for the same \p func. - LazyContextData *getOrCreateLazyContextData(const Decl *decl, + LazyContextData *getOrCreateLazyContextData(const DeclContext *decl, LazyMemberLoader *lazyLoader); - /// Get the lazy function data for the given generic type. - /// - /// \param lazyLoader If non-null, the lazy loader to use when creating the - /// generic type data. The pointer must either be null or be consistent - /// across all calls for the same \p type. - LazyGenericTypeData *getOrCreateLazyGenericTypeData( - const GenericTypeDecl *type, - LazyMemberLoader *lazyLoader); - - /// Get the lazy function data for the given abstract function. + /// Get the lazy function data for the given generic context. /// /// \param lazyLoader If non-null, the lazy loader to use when creating the /// function data. The pointer must either be null or be consistent /// across all calls for the same \p func. - LazyAbstractFunctionData *getOrCreateLazyFunctionContextData( - const AbstractFunctionDecl *func, + LazyGenericContextData *getOrCreateLazyGenericContextData( + const GenericContext *dc, LazyMemberLoader *lazyLoader); /// Get the lazy iterable context for the given iterable declaration context. diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index 14a99ffb66185..275ef9e4e710a 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -191,22 +191,15 @@ class LazyContextData { LazyMemberLoader *loader; }; -/// Context data for abstract function declarations. -class LazyAbstractFunctionData : public LazyContextData { -public: - /// The context data used for loading the generic environment. - uint64_t genericEnvData = 0; -}; - -/// Context data for generic type declarations. -class LazyGenericTypeData : public LazyContextData { +/// Context data for generic contexts. +class LazyGenericContextData : public LazyContextData { public: /// The context data used for loading the generic environment. uint64_t genericEnvData = 0; }; /// Context data for iterable decl contexts. -class LazyIterableDeclContextData : public LazyGenericTypeData { +class LazyIterableDeclContextData : public LazyGenericContextData { public: /// The context data used for loading all of the members of the iterable /// context. @@ -254,7 +247,7 @@ class alignas(void*) LazyMemberLoader { } /// Returns the generic environment. - virtual GenericEnvironment *loadGenericEnvironment(const Decl *decl, + virtual GenericEnvironment *loadGenericEnvironment(const DeclContext *decl, uint64_t contextData) { llvm_unreachable("unimplemented"); } diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h index aab2b704a06d6..0d64e9b8a9df1 100644 --- a/include/swift/Serialization/ModuleFile.h +++ b/include/swift/Serialization/ModuleFile.h @@ -507,8 +507,7 @@ class ModuleFile : public LazyMemberLoader { /// Set up a (potentially lazy) generic environment for the given type, /// function or extension. void configureGenericEnvironment( - llvm::PointerUnion3 genericDecl, + GenericContext *genericDecl, serialization::GenericEnvironmentID envID); /// Populates the vector with members of a DeclContext from \c DeclTypeCursor. @@ -711,7 +710,7 @@ class ModuleFile : public LazyMemberLoader { virtual void finishNormalConformance(NormalProtocolConformance *conformance, uint64_t contextData) override; - GenericEnvironment *loadGenericEnvironment(const Decl *decl, + GenericEnvironment *loadGenericEnvironment(const DeclContext *decl, uint64_t contextData) override; Optional getGroupNameById(unsigned Id) const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4686da9948a83..70f5135a6c738 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -206,7 +206,7 @@ struct ASTContext::Implementation { DelayedConformanceDiags; /// Stores information about lazy deserialization of various declarations. - llvm::DenseMap LazyContexts; + llvm::DenseMap LazyContexts; /// Stored generic signature builders for canonical generic signatures. llvm::DenseMap, @@ -1477,9 +1477,9 @@ ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) { } LazyContextData *ASTContext::getOrCreateLazyContextData( - const Decl *decl, + const DeclContext *dc, LazyMemberLoader *lazyLoader) { - auto known = Impl.LazyContexts.find(decl); + auto known = Impl.LazyContexts.find(dc); if (known != Impl.LazyContexts.end()) { // Make sure we didn't provide an incompatible lazy loader. assert(!lazyLoader || lazyLoader == known->second->loader); @@ -1488,30 +1488,18 @@ LazyContextData *ASTContext::getOrCreateLazyContextData( // Create new lazy iterable context data with the given loader. assert(lazyLoader && "Queried lazy data for non-lazy iterable context"); - if (isa(decl) || isa(decl)) { + if (isa(dc) || isa(dc)) { auto *contextData = Allocate(); contextData->loader = lazyLoader; - Impl.LazyContexts[decl] = contextData; + Impl.LazyContexts[dc] = contextData; return contextData; } - // Create new lazy generic type data with the given loader. - if (isa(decl)) { - auto *contextData = Allocate(); - contextData->loader = lazyLoader; - Impl.LazyContexts[decl] = contextData; - return contextData; - } - - // Create new lazy function context data with the given loader. - if (isa(decl)) { - auto *contextData = Allocate(); - contextData->loader = lazyLoader; - Impl.LazyContexts[decl] = contextData; - return contextData; - } - - llvm_unreachable("unhandled lazy context"); + // Create new lazy generic context data with the given loader. + auto *contextData = Allocate(); + contextData->loader = lazyLoader; + Impl.LazyContexts[dc] = contextData; + return contextData; } LazyIterableDeclContextData *ASTContext::getOrCreateLazyIterableContextData( @@ -1527,18 +1515,13 @@ LazyIterableDeclContextData *ASTContext::getOrCreateLazyIterableContextData( lazyLoader); } -LazyAbstractFunctionData *ASTContext::getOrCreateLazyFunctionContextData( - const AbstractFunctionDecl *func, +LazyGenericContextData *ASTContext::getOrCreateLazyGenericContextData( + const GenericContext *dc, LazyMemberLoader *lazyLoader) { - return (LazyAbstractFunctionData *)getOrCreateLazyContextData(func, - lazyLoader); + return (LazyGenericContextData *)getOrCreateLazyContextData(dc, + lazyLoader); } -LazyGenericTypeData *ASTContext::getOrCreateLazyGenericTypeData( - const GenericTypeDecl *type, - LazyMemberLoader *lazyLoader) { - return (LazyGenericTypeData *)getOrCreateLazyContextData(type, lazyLoader); -} void ASTContext::addDelayedConformanceDiag( NormalProtocolConformance *conformance, DelayedConformanceDiag fn) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 86eeff0222c34..9f4c2dc0c75c0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -592,26 +592,10 @@ GenericContext::getLazyGenericEnvironmentSlow() const { assert(GenericSigOrEnv.is() && "not a lazily deserialized generic environment"); - GenericEnvironment *genericEnv; - - if (auto *extensionDecl = dyn_cast(this)) { - auto contextData = getASTContext().getOrCreateLazyIterableContextData( - extensionDecl, nullptr); - genericEnv = contextData->loader->loadGenericEnvironment( - extensionDecl, contextData->genericEnvData); - } else if (auto *typeDecl = dyn_cast(this)) { - auto contextData = getASTContext().getOrCreateLazyGenericTypeData( - typeDecl, nullptr); - genericEnv = contextData->loader->loadGenericEnvironment( - typeDecl, contextData->genericEnvData); - } else if (auto *funcDecl = dyn_cast(this)) { - auto contextData = getASTContext().getOrCreateLazyFunctionContextData( - funcDecl, nullptr); - genericEnv = contextData->loader->loadGenericEnvironment( - funcDecl, contextData->genericEnvData); - } else { - llvm_unreachable("Bad GenericContext kind"); - } + auto contextData = getASTContext().getOrCreateLazyGenericContextData( + this, nullptr); + auto *genericEnv = contextData->loader->loadGenericEnvironment( + this, contextData->genericEnvData); const_cast(this)->setGenericEnvironment(genericEnv); ++NumLazyGenericEnvironmentsLoaded; @@ -624,24 +608,9 @@ void GenericContext::setLazyGenericEnvironment(LazyMemberLoader *lazyLoader, assert(GenericSigOrEnv.isNull() && "already have a generic signature"); GenericSigOrEnv = genericSig; - if (auto *extensionDecl = dyn_cast(this)) { - auto contextData = - getASTContext().getOrCreateLazyIterableContextData( - extensionDecl, lazyLoader); - contextData->genericEnvData = genericEnvData; - } else if (auto *typeDecl = dyn_cast(this)) { - auto contextData = - getASTContext().getOrCreateLazyGenericTypeData( - typeDecl, lazyLoader); - contextData->genericEnvData = genericEnvData; - } else if (auto *funcDecl = dyn_cast(this)) { - auto contextData = - getASTContext().getOrCreateLazyFunctionContextData( - funcDecl, lazyLoader); - contextData->genericEnvData = genericEnvData; - } else { - llvm_unreachable("Bad GenericContext kind"); - } + auto contextData = + getASTContext().getOrCreateLazyGenericContextData(this, lazyLoader); + contextData->genericEnvData = genericEnvData; ++NumLazyGenericEnvironments; } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 13c451000b228..3fc604d0ca7b4 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -992,8 +992,7 @@ void ModuleFile::readGenericRequirements( } void ModuleFile::configureGenericEnvironment( - llvm::PointerUnion3 genericDecl, + GenericContext *genericDecl, serialization::GenericEnvironmentID envID) { if (envID == 0) return; @@ -1002,33 +1001,15 @@ void ModuleFile::configureGenericEnvironment( // If we just have a generic signature, set up lazy generic environment // creation. if (auto genericSig = sigOrEnv.dyn_cast()) { - if (auto type = genericDecl.dyn_cast()) { - type->setLazyGenericEnvironment(this, genericSig, envID); - DelayedGenericEnvironments.push_back(type); - } else if (auto func = genericDecl.dyn_cast()) { - func->setLazyGenericEnvironment(this, genericSig, envID); - DelayedGenericEnvironments.push_back(func); - } else { - auto ext = genericDecl.get(); - ext->setLazyGenericEnvironment(this, genericSig, envID); - DelayedGenericEnvironments.push_back(ext); - } - + genericDecl->setLazyGenericEnvironment(this, genericSig, envID); + DelayedGenericEnvironments.push_back(genericDecl); return; } // If we have a full generic environment, it's because it happened to be // deserialized already. Record it directly. if (auto genericEnv = sigOrEnv.dyn_cast()) { - if (auto type = genericDecl.dyn_cast()) { - type->setGenericEnvironment(genericEnv); - } else if (auto func = genericDecl.dyn_cast()) { - func->setGenericEnvironment(genericEnv); - } else { - auto ext = genericDecl.get(); - ext->setGenericEnvironment(genericEnv); - } - + genericDecl->setGenericEnvironment(genericEnv); return; } } @@ -4441,7 +4422,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, } } -GenericEnvironment *ModuleFile::loadGenericEnvironment(const Decl *decl, +GenericEnvironment *ModuleFile::loadGenericEnvironment(const DeclContext *decl, uint64_t contextData) { return getGenericEnvironment(contextData); } From 880803aaba001d77bcaa28b8ce8b36149f0e96ad Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 19 Feb 2017 20:33:46 -0800 Subject: [PATCH 3/4] AST: Initial plumbing for generic subscripts --- include/swift/AST/Decl.h | 8 +++++--- lib/AST/DeclContext.cpp | 27 +++++++++++++++++++++------ lib/ClangImporter/ImportDecl.cpp | 6 ++++-- lib/Parse/ParseDecl.cpp | 3 ++- lib/Sema/TypeCheckDecl.cpp | 3 +++ lib/Serialization/Deserialization.cpp | 4 +++- 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 6f6b78acb1b79..950f674d3abee 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4527,18 +4527,20 @@ enum class ObjCSubscriptKind { /// A given type can have multiple subscript declarations, so long as the /// signatures (indices and element type) are distinct. /// -class SubscriptDecl : public AbstractStorageDecl, public DeclContext { +class SubscriptDecl : public AbstractStorageDecl, public GenericContext { SourceLoc ArrowLoc; ParameterList *Indices; TypeLoc ElementTy; public: SubscriptDecl(DeclName Name, SourceLoc SubscriptLoc, ParameterList *Indices, - SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent) + SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent, + GenericParamList *GenericParams) : AbstractStorageDecl(DeclKind::Subscript, Parent, Name, SubscriptLoc), - DeclContext(DeclContextKind::SubscriptDecl, Parent), + GenericContext(DeclContextKind::SubscriptDecl, Parent), ArrowLoc(ArrowLoc), Indices(nullptr), ElementTy(ElementTy) { setIndices(Indices); + setGenericParams(GenericParams); } SourceLoc getSubscriptLoc() const { return getNameLoc(); } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index a551ef09be96c..34740f76cfa4f 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -193,11 +193,15 @@ GenericParamList *DeclContext::getGenericParamsOfContext() const { case DeclContextKind::SerializedLocal: case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::SubscriptDecl: // Closures and initializers can't themselves be generic, but they // can occur in generic contexts. continue; + case DeclContextKind::SubscriptDecl: + if (auto GP = cast(dc)->getGenericParams()) + return GP; + continue; + case DeclContextKind::AbstractFunctionDecl: if (auto GP = cast(dc)->getGenericParams()) return GP; @@ -228,11 +232,13 @@ GenericSignature *DeclContext::getGenericSignatureOfContext() const { case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::SubscriptDecl: // Closures and initializers can't themselves be generic, but they // can occur in generic contexts. continue; + case DeclContextKind::SubscriptDecl: + return cast(dc)->getGenericSignature(); + case DeclContextKind::AbstractFunctionDecl: return cast(dc)->getGenericSignature(); @@ -257,11 +263,13 @@ GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const { case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::SubscriptDecl: // Closures and initializers can't themselves be generic, but they // can occur in generic contexts. continue; + case DeclContextKind::SubscriptDecl: + return cast(dc)->getGenericEnvironment(); + case DeclContextKind::AbstractFunctionDecl: return cast(dc)->getGenericEnvironment(); @@ -435,7 +443,12 @@ bool DeclContext::isGenericContext() const { case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: case DeclContextKind::SerializedLocal: + // Check parent context. + continue; + case DeclContextKind::SubscriptDecl: + if (cast(dc)->getGenericParams()) + return true; // Check parent context. continue; @@ -516,12 +529,14 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const { /// Determine whether the innermost context is generic. bool DeclContext::isInnermostContextGeneric() const { switch (getContextKind()) { + case DeclContextKind::SubscriptDecl: + return cast(this)->isGeneric(); case DeclContextKind::AbstractFunctionDecl: - return (cast(this)->getGenericParams() != nullptr); + return cast(this)->isGeneric(); case DeclContextKind::ExtensionDecl: - return (cast(this)->getGenericParams() != nullptr); + return cast(this)->isGeneric(); case DeclContextKind::GenericTypeDecl: - return (cast(this)->getGenericParams() != nullptr); + return cast(this)->isGeneric(); default: return false; } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 0a490f0df8c02..aa15f25f20d37 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -5984,16 +5984,18 @@ SwiftDeclConverter::importSubscript(Decl *decl, auto subscript = Impl.createDeclWithClangNode( getter->getClangNode(), getOverridableAccessibility(dc), name, decl->getLoc(), bodyParams, decl->getLoc(), - TypeLoc::withoutLoc(elementContextTy), dc); + TypeLoc::withoutLoc(elementContextTy), dc, + /*GenericParams=*/nullptr); /// Record the subscript as an alternative declaration. Impl.addAlternateDecl(associateWithSetter ? setter : getter, subscript); + subscript->setGenericEnvironment(dc->getGenericEnvironmentOfContext()); + subscript->makeComputed(SourceLoc(), getterThunk, setterThunk, nullptr, SourceLoc()); auto indicesType = bodyParams->getType(C); - // TODO: no good when generics are around auto fnType = FunctionType::get(indicesType, elementTy); subscript->setInterfaceType(fnType); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ffba66b6fb101..d55b5a9384109 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5442,7 +5442,8 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, auto *Subscript = new (Context) SubscriptDecl(name, SubscriptLoc, Indices.get(), ArrowLoc, ElementTy.get(), - CurDeclContext); + CurDeclContext, + /*GenericParams=*/nullptr); Subscript->getAttrs() = Attributes; Decls.push_back(Subscript); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index dc4300470c0a8..44f7c6ad7ecef 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3887,6 +3887,9 @@ class DeclChecker : public DeclVisitor { assert(dc->isTypeContext() && "Decl parsing must prevent subscripts outside of types!"); + // Inherit the generic signature and environment from the outer context. + SD->setGenericEnvironment(dc->getGenericEnvironmentOfContext()); + TC.checkDeclAttributesEarly(SD); TC.computeAccessibility(SD); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 3fc604d0ca7b4..4a528b2c74d08 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3379,8 +3379,10 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { argNames.push_back(getIdentifier(argNameID)); DeclName name(ctx, ctx.Id_subscript, argNames); + // FIXME: Serialize generic subscripts auto subscript = createDecl(name, SourceLoc(), nullptr, - SourceLoc(), TypeLoc(), DC); + SourceLoc(), TypeLoc(), DC, + /*GenericParams=*/nullptr); declOrOffset = subscript; subscript->setIndices(readParameterList()); From cc54361b2a2832885adaea38fb5bcaf6e363a2a8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 19 Feb 2017 20:26:50 -0800 Subject: [PATCH 4/4] Serialization: Add support for generic subscripts --- include/swift/Serialization/ModuleFormat.h | 7 +++++-- lib/Serialization/Deserialization.cpp | 15 +++++++++++---- lib/Serialization/Serialization.cpp | 3 +++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 5178e6adc6654..31010a51d0bb9 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0; /// in source control, you should also update the comment to briefly /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. -const uint16_t VERSION_MINOR = 318; // Last change: SIL open_exist. access kind +const uint16_t VERSION_MINOR = 319; // Last change: generic subscripts using DeclID = PointerEmbeddedInt; using DeclIDField = BCFixed<31>; @@ -976,6 +976,7 @@ namespace decls_block { BCFixed<1>, // implicit? BCFixed<1>, // objc? StorageKindField, // StorageKind + GenericEnvironmentIDField, // generic environment TypeIDField, // interface type DeclIDField, // getter DeclIDField, // setter @@ -988,7 +989,9 @@ namespace decls_block { AccessibilityKindField, // accessibility AccessibilityKindField, // setter accessibility, if applicable BCArray // name components - // The indices pattern trails the record. + // Trailed by: + // - generic parameters, if any + // - the indices pattern >; using ExtensionLayout = BCRecordLayout< diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 4a528b2c74d08..a62ff972b52c5 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3351,6 +3351,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { case decls_block::SUBSCRIPT_DECL: { DeclContextID contextID; bool isImplicit, isObjC; + GenericEnvironmentID genericEnvID; TypeID interfaceTypeID; DeclID getterID, setterID, materializeForSetID; DeclID addressorID, mutableAddressorID, willSetID, didSetID; @@ -3361,6 +3362,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { decls_block::SubscriptLayout::readRecord(scratch, contextID, isImplicit, isObjC, rawStorageKind, + genericEnvID, interfaceTypeID, getterID, setterID, materializeForSetID, @@ -3369,7 +3371,11 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { overriddenID, rawAccessLevel, rawSetterAccessLevel, argNameIDs); - auto DC = getDeclContext(contextID); + auto parent = getDeclContext(contextID); + if (declOrOffset.isComplete()) + return declOrOffset; + + auto *genericParams = maybeReadGenericParams(parent); if (declOrOffset.isComplete()) return declOrOffset; @@ -3379,12 +3385,13 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { argNames.push_back(getIdentifier(argNameID)); DeclName name(ctx, ctx.Id_subscript, argNames); - // FIXME: Serialize generic subscripts auto subscript = createDecl(name, SourceLoc(), nullptr, - SourceLoc(), TypeLoc(), DC, - /*GenericParams=*/nullptr); + SourceLoc(), TypeLoc(), + parent, genericParams); declOrOffset = subscript; + configureGenericEnvironment(subscript, genericEnvID); + subscript->setIndices(readParameterList()); configureStorage(subscript, rawStorageKind, diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 5a0cdffffa281..7deeb0f371b83 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2884,6 +2884,8 @@ void Serializer::writeDecl(const Decl *D) { subscript->isImplicit(), subscript->isObjC(), (unsigned) accessors.Kind, + addGenericEnvironmentRef( + subscript->getGenericEnvironment()), addTypeRef(subscript->getInterfaceType()), addDeclRef(accessors.Get), addDeclRef(accessors.Set), @@ -2897,6 +2899,7 @@ void Serializer::writeDecl(const Decl *D) { rawSetterAccessLevel, nameComponents); + writeGenericParams(subscript->getGenericParams()); writeParameterList(subscript->getIndices()); break; }