From c4e265e28024f45d7994abba93b8474400a7e5cb Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 20 Jan 2021 09:57:17 -0800 Subject: [PATCH] [Type checker] Add "all members" request. Introduce an "all members" request to compute all of the members of a given iterable declaration context in stable order. This builds on ABI members so that it will also include, e.g., type aliases synthesized for associated types. --- include/swift/AST/DeclContext.h | 6 ++ include/swift/AST/TypeCheckRequests.h | 18 ++++++ include/swift/AST/TypeCheckerTypeIDZone.def | 2 + lib/AST/DeclContext.cpp | 8 +++ lib/Sema/TypeCheckDecl.cpp | 70 +++++++++++++++++---- lib/Sema/TypeCheckDeclPrimary.cpp | 2 +- 6 files changed, 92 insertions(+), 14 deletions(-) diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index d6e52978109..e3a85c0f0e2 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -784,6 +784,12 @@ public: /// The resulting list of members will be stable across translation units. ArrayRef getABIMembers() const; + /// Get all of the members within this context, including any + /// implicitly-synthesized members. + /// + /// The resulting list of members will be stable across translation units. + ArrayRef getAllMembers() const; + /// Retrieve the set of members in this context without loading any from the /// associated lazy loader; this should only be used as part of implementing /// abstractions on top of member loading, such as a name lookup table. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index aaaa6ad71f5..f09909baa74 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1238,6 +1238,24 @@ public: bool isCached() const { return true; } }; +class AllMembersRequest : + public SimpleRequest(IterableDeclContext *), + RequestFlags::Cached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + ArrayRef + evaluate(Evaluator &evaluator, IterableDeclContext *idc) const; + +public: + bool isCached() const { return true; } +}; + class IsImplicitlyUnwrappedOptionalRequest : public SimpleRequest(IterableDeclContext *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, AllMembersRequest, + ArrayRef(IterableDeclContext *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SpecializeAttrTargetDeclRequest, ValueDecl *(const ValueDecl *, SpecializeAttr *), Cached, NoLocationInfo) diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 7001d6ed5f7..8239cfcdcee 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -766,6 +766,14 @@ ArrayRef IterableDeclContext::getABIMembers() const { ArrayRef()); } +ArrayRef IterableDeclContext::getAllMembers() const { + ASTContext &ctx = getASTContext(); + return evaluateOrDefault( + ctx.evaluator, + AllMembersRequest{const_cast(this)}, + ArrayRef()); +} + void IterableDeclContext::addMemberPreservingSourceOrder(Decl *member) { auto &SM = getASTContext().SourceMgr; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 5a68ed8c048..1357109d5e4 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2550,14 +2550,23 @@ struct SortedDeclList { } // end namespace -ArrayRef -ABIMembersRequest::evaluate( - Evaluator &evaluator, IterableDeclContext *idc) const { +namespace { + enum class MembersRequestKind { + ABI, + All, + }; + +} + +/// Evaluate a request for a particular set of members of an iterable +/// declaration context. +static ArrayRef evaluateMembersRequest( + IterableDeclContext *idc, MembersRequestKind kind) { auto dc = cast(idc->getDecl()); - auto &Context = dc->getASTContext(); + auto &ctx = dc->getASTContext(); SmallVector result; - // Esnure that we add any synthesized members. + // Ensure that we add any synthesized members. if (dc->getParentSourceFile()) { auto nominal = dyn_cast(idc); @@ -2567,12 +2576,35 @@ ABIMembersRequest::evaluate( TypeChecker::addImplicitConstructors(nominal); } - // Force any derivable conformances in this context. This ensures that any - // synthesized members will approach in the member list. + // Force any conformances that may introduce more members. for (auto conformance : idc->getLocalConformances()) { - if (conformance->getState() == ProtocolConformanceState::Incomplete && - conformance->getProtocol()->getKnownDerivableProtocolKind()) - TypeChecker::checkConformance(conformance->getRootNormalConformance()); + auto proto = conformance->getProtocol(); + bool isDerivable = + conformance->getState() == ProtocolConformanceState::Incomplete && + proto->getKnownDerivableProtocolKind(); + + switch (kind) { + case MembersRequestKind::ABI: + // Force any derivable conformances in this context. + if (isDerivable) + break; + + continue; + + case MembersRequestKind::All: + // Force any derivable conformances. + if (isDerivable) + break; + + // If there are any associated types in the protocol, they might add + // type aliases here. + if (!proto->getAssociatedTypeMembers().empty()) + break; + + continue; + } + + TypeChecker::checkConformance(conformance->getRootNormalConformance()); } // If the type conforms to Encodable or Decodable, even via an extension, @@ -2580,7 +2612,7 @@ ABIMembersRequest::evaluate( // Force it into existence. if (nominal) { (void) evaluateOrDefault( - Context.evaluator, + ctx.evaluator, ResolveImplicitMemberRequest{nominal, ImplicitMemberAction::ResolveCodingKeys}, {}); @@ -2589,7 +2621,7 @@ ABIMembersRequest::evaluate( // If the decl has a @main attribute, we need to force synthesis of the // $main function. (void) evaluateOrDefault( - Context.evaluator, + ctx.evaluator, SynthesizeMainFunctionRequest{const_cast(idc->getDecl())}, nullptr); @@ -2633,7 +2665,19 @@ ABIMembersRequest::evaluate( result.push_back(pair.second); } - return Context.AllocateCopy(result); + return ctx.AllocateCopy(result); +} + +ArrayRef +ABIMembersRequest::evaluate( + Evaluator &evaluator, IterableDeclContext *idc) const { + return evaluateMembersRequest(idc, MembersRequestKind::ABI); +} + +ArrayRef +AllMembersRequest::evaluate( + Evaluator &evaluator, IterableDeclContext *idc) const { + return evaluateMembersRequest(idc, MembersRequestKind::All); } bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 0cecae466f2..3e2f4232485 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2129,7 +2129,7 @@ public: TypeChecker::checkDeclAttributes(CD); - for (Decl *Member : CD->getABIMembers()) + for (Decl *Member : CD->getAllMembers()) visit(Member); TypeChecker::checkPatternBindingCaptures(CD);