//===--- ASTScopeImpl.h - Swift AST Object-Oriented Scope --------*- C++-*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// /// This file defines the ASTScopeImpl class ontology, which /// describes the scopes that exist within a Swift AST. /// /// Each scope has four basic functions: printing for debugging, creation of /// itself and its children, obtaining its SourceRange (for lookup), and looking /// up names accessible from that scope. /// /// Invariants: /// a child's source range is a subset (proper or improper) of its parent's, /// children are ordered by source range, and do not overlap, /// all the names visible within a parent are visible within the child, unless /// the nesting is illegal. For instance, a protocol nested inside of a class /// does not get to see the symbols in the class or its ancestors. /// //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_AST_SCOPE_H #define SWIFT_AST_AST_SCOPE_H #include "swift/AST/ASTNode.h" #include "swift/AST/CatchNode.h" #include "swift/AST/NameLookup.h" #include "swift/AST/SimpleRequest.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/Debug.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/NullablePtr.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include /// In case there's a bug in the ASTScope lookup system, suggest that the user /// try disabling it. /// \p message must be a string literal #define ASTScopeAssert(predicate, message) \ assert((predicate) && message) #define ASTScope_unreachable(message) \ llvm_unreachable(message) namespace swift { #pragma mark Forward-references #define DECL(Id, Parent) class Id##Decl; #define ABSTRACT_DECL(Id, Parent) class Id##Decl; #include "swift/AST/DeclNodes.def" #undef DECL #undef ABSTRACT_DECL #define EXPR(Id, Parent) class Id##Expr; #include "swift/AST/ExprNodes.def" #undef EXPR #define STMT(Id, Parent) class Id##Stmt; #define ABSTRACT_STMT(Id, Parent) class Id##Stmt; #include "swift/AST/StmtNodes.def" #undef STMT #undef ABSTRACT_STMT class GenericParamList; class TrailingWhereClause; class ParameterList; class PatternBindingEntry; class SpecializeAttr; class GenericContext; class DeclName; class StmtConditionElement; namespace Lowering { class SILGenFunction; } namespace ast_scope { class ASTScopeImpl; class BraceStmtScope; class GenericTypeOrExtensionScope; class IterableTypeScope; class TypeAliasScope; class ScopeCreator; struct AnnotatedInsertionPoint { ASTScopeImpl *insertionPoint; const char *explanation; }; } // namespace ast_scope namespace ast_scope { void simple_display(llvm::raw_ostream &out, const ASTScopeImpl *); void simple_display(llvm::raw_ostream &out, const ScopeCreator *); SourceLoc extractNearestSourceLoc(std::tuple); /// Enumerate the different kinds of ASTScope implementation nodes. enum class ScopeKind { #define SCOPE_NODE(Name) Name, #include "swift/AST/ASTScopeNodes.def" }; #pragma mark the root ASTScopeImpl class /// Describes a lexical scope within a source file. /// /// Each \c ASTScopeImpl is a node within a tree that describes all of the /// lexical scopes within a particular source range. The root of this scope tree /// is always a \c SourceFile node, and the tree covers the entire source file. /// The children of a particular node are the lexical scopes immediately /// nested within that node, and have source ranges that are enclosed within /// the source range of their parent node. At the leaves are lexical scopes /// that cannot be subdivided further. /// /// The tree provides source-location-based query operations, allowing one to /// find the innermost scope that contains a given source location. Navigation /// to parent nodes from that scope allows one to walk the lexically enclosing /// scopes outward to the source file. Given a scope, one can also query the /// associated \c DeclContext for additional contextual information. /// /// \code /// -dump-scope-maps expanded /// \endcode class ASTScopeImpl : public ASTAllocated { friend class NodeAdder; friend class Portion; friend class GenericTypeOrExtensionWholePortion; friend class NomExtDeclPortion; friend class GenericTypeOrExtensionWherePortion; friend class GenericTypeOrExtensionWherePortion; friend class IterableTypeBodyPortion; friend class ScopeCreator; friend class ASTSourceFileScope; friend class Lowering::SILGenFunction; #pragma mark - tree state protected: using Children = SmallVector; /// Whether the given parent is the accessor node for an abstract /// storage declaration or is directly descended from it. private: /// The kind of scope node. ScopeKind kind; /// The pointer: /// - Always set by the constructor, so that when creating a child /// the parent chain is available. Null at the root. /// The int: /// - A flag indicating if the scope has been expanded yet or not. llvm::PointerIntPair parentAndWasExpanded; /// Child scopes, sorted by source range. Children storedChildren; mutable std::optional cachedCharSourceRange; #pragma mark - constructor / destructor public: ASTScopeImpl(ScopeKind kind) : kind(kind) { } // TOD: clean up all destructors and deleters virtual ~ASTScopeImpl() {} ASTScopeImpl(ASTScopeImpl &&) = delete; ASTScopeImpl &operator=(ASTScopeImpl &&) = delete; ASTScopeImpl(const ASTScopeImpl &) = delete; ASTScopeImpl &operator=(const ASTScopeImpl &) = delete; // Need this because have virtual destructors void operator delete(void *data) {} #pragma mark - tree declarations protected: NullablePtr getParent() { return parentAndWasExpanded.getPointer(); } NullablePtr getParent() const { return parentAndWasExpanded.getPointer(); } public: const Children &getChildren() const { return storedChildren; } void addChild(ASTScopeImpl *child, ASTContext &); public: void preOrderDo(function_ref); /// Like preorderDo but without myself. void preOrderChildrenDo(function_ref); void postOrderDo(function_ref); #pragma mark - source ranges public: /// Retrieve the source range of the given scope, where the end location /// is adjusted to refer to the end of the token. /// /// Since the adjustment to the end of the token requires lexing, this /// routine also caches the result. /// /// Note that the start and end locations might be in different source /// buffers, so we represent the result as SourceRange rather than /// CharSourceRange. SourceRange getCharSourceRangeOfScope(SourceManager &SM, bool omitAssertions = false) const; bool isCharSourceRangeCached() const; /// Returns source range of this node alone, without factoring in any /// children. virtual SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0; protected: SourceManager &getSourceManager() const; private: void checkSourceRangeBeforeAddingChild(ASTScopeImpl *child, const ASTContext &ctx) const; #pragma mark common queries public: /// Determine the kind of scope node we have. ScopeKind getKind() const { return kind; } ASTContext &getASTContext() const; NullablePtr getDeclIfAny() const; NullablePtr getStmtIfAny() const; NullablePtr getExprIfAny() const; #pragma mark - debugging and printing public: const SourceFile *getSourceFile() const; std::string getClassName() const; /// Print out this scope for debugging/reporting purposes. void print(llvm::raw_ostream &out, unsigned level = 0, bool lastChild = false, bool printChildren = true) const; void printRange(llvm::raw_ostream &out) const; protected: virtual void printSpecifics(llvm::raw_ostream &out) const {} virtual NullablePtr addressForPrinting() const; public: SWIFT_DEBUG_DUMP; void dumpOneScopeMapLocation(std::pair lineColumn); private: llvm::raw_ostream &verificationError() const; #pragma mark - Scope tree creation public: /// Expand the scope if unexpanded. ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); bool getWasExpanded() const { return parentAndWasExpanded.getInt(); } protected: void setWasExpanded() { parentAndWasExpanded.setInt(1); } virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; public: /// Some scopes can be expanded lazily. /// Such scopes must return an insertion point outside themselves when /// expanded. virtual NullablePtr insertionPointForDeferredExpansion(); private: virtual ScopeCreator &getScopeCreator(); #pragma mark - lookup public: using DeclConsumer = namelookup::AbstractASTScopeDeclConsumer &; /// Entry point into ASTScopeImpl-land for lookups static void unqualifiedLookup(SourceFile *, SourceLoc, DeclConsumer); /// Entry point into ASTScopeImpl-land for labeled statement lookups. static llvm::SmallVector lookupLabeledStmts(SourceFile *sourceFile, SourceLoc loc); static std::pair lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc); static void lookupEnclosingMacroScope( SourceFile *sourceFile, SourceLoc loc, llvm::function_ref consume); static CatchNode lookupCatchNode(ModuleDecl *module, SourceLoc loc); /// Scopes that cannot bind variables may set this to true to create more /// compact scope tree in the debug info. virtual bool ignoreInDebugInfo() const { return false; } #pragma mark - - lookup- starting point private: static const ASTScopeImpl *findStartingScopeForLookup(SourceFile *, const SourceLoc where); protected: /// Not const because may reexpand some scopes. ASTScopeImpl *findInnermostEnclosingScope(ModuleDecl *, SourceLoc, NullablePtr); ASTScopeImpl *findInnermostEnclosingScopeImpl(ModuleDecl *, SourceLoc, NullablePtr, SourceManager &, ScopeCreator &); private: NullablePtr findChildContaining(ModuleDecl *, SourceLoc loc, SourceManager &sourceMgr) const; #pragma mark - - lookup- per scope protected: /// The main (recursive) lookup function: /// Tell DeclConsumer about all names found in this scope and if not done, /// recurse for enclosing scopes. Stop lookup if about to look in limit. /// /// If the lookup depends on implicit self, selfDC is its context. /// (Names in extensions never depend on self.) /// /// In a Nominal, Extension, or TypeAliasScope, the lookup can start at either /// the body portion (for the first two), the where portion, or a /// GenericParamScope. In every case, the generics on the type decl must be /// searched, but only once. And they must be searched *before* the generic /// parameters. For instance, the following is correct: \code class /// ShadowingGenericParameter { \code typealias T = Int; func foo (t : /// T) {} \code } \code ShadowingGenericParameter().foo(t: "hi") /// /// So keep track of the last generic param list searched to avoid /// duplicating work. /// /// Look in this scope. /// \param limit A scope into which lookup should not go. See \c /// getLookupLimit. \param lastListSearched Last list searched. /// \param consumer is the object to which found decls are reported. void lookup(NullablePtr limit, NullablePtr lastListSearched, DeclConsumer consumer) const; protected: /// Find either locals or members (no scope has both) /// \return True if lookup is done virtual bool lookupLocalsOrMembers(DeclConsumer consumer) const; /// Returns isDone and the list searched, if any std::pair> lookInMyGenericParameters( NullablePtr priorListSearched, DeclConsumer consumer) const; virtual NullablePtr genericParams() const; // Consume the generic parameters in the context and its outer contexts static bool lookInGenericParametersOf(NullablePtr, DeclConsumer); NullablePtr parentIfNotChildOfTopScope() const { const auto *p = getParent().get(); return p->getParent().isNonNull() ? p : nullptr; } public: /// The tree is organized by source location and for most nodes this is also /// what obtains for scoping. However, guards are different. The scope after /// the guard else must hop into the innermoset scope of the guard condition. virtual NullablePtr getLookupParent() const { return getParent(); } #pragma mark - - lookup- local bindings protected: // A local binding is a basically a local variable defined in that very scope // It is not an instance variable or inherited type. static bool lookupLocalBindingsInPattern(const Pattern *p, DeclConsumer consumer); /// When lookup must stop before the outermost scope, return the scope to stop /// at. Example, if a protocol is nested in a struct, we must stop before /// looking into the struct. /// /// Ultimately, the task of rejecting results found in inapplicable outer /// scopes is best moved to the clients of the ASTScope lookup subsystem. It /// seems out of place here. virtual NullablePtr getLookupLimit() const; NullablePtr ancestorWithDeclSatisfying(function_ref predicate) const; /// Whether this scope terminates lookup of labeled statements in the /// children below it, because one cannot perform a "break" or a "continue" /// in a child that goes outside of this scope. virtual bool isLabeledStmtLookupTerminator() const; }; // end of ASTScopeImpl #pragma mark - specific scope classes /// The root of the scope tree. class ASTSourceFileScope final : public ASTScopeImpl { public: SourceFile *const SF; ScopeCreator *const scopeCreator; ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator); SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: void buildFullyExpandedTree(); void buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); void expandFunctionBody(AbstractFunctionDecl *AFD); NullablePtr addressForPrinting() const override { return SF; } bool ignoreInDebugInfo() const override { return true; } protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; ScopeCreator &getScopeCreator() override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ASTSourceFile; } }; class Portion : public ASTAllocated { public: const char *portionName; Portion(const char *n) : portionName(n) {} virtual ~Portion() {} // Need this because have virtual destructors void operator delete(void *data) {} /// Return the new insertion point virtual ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const = 0; /// \Returns \c true if this lookup is done looking for results, else \c false. virtual SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *scope, bool omitAssertions) const = 0; virtual bool lookupMembersOf(const GenericTypeOrExtensionScope *scope, ASTScopeImpl::DeclConsumer consumer) const; virtual NullablePtr getLookupLimitFor(const GenericTypeOrExtensionScope *) const; virtual NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const = 0; }; // For the whole Decl scope of a GenericType or an Extension class GenericTypeOrExtensionWholePortion final : public Portion { public: GenericTypeOrExtensionWholePortion() : Portion("Decl") {} virtual ~GenericTypeOrExtensionWholePortion() {} // Just for TypeAlias ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const override; SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, bool omitAssertions) const override; NullablePtr getLookupLimitFor(const GenericTypeOrExtensionScope *) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; }; /// Behavior specific to representing the trailing where clause of a /// GenericTypeDecl or ExtensionDecl scope. class GenericTypeOrExtensionWherePortion final : public Portion { public: GenericTypeOrExtensionWherePortion() : Portion("Where") {} bool lookupMembersOf(const GenericTypeOrExtensionScope *scope, ASTScopeImpl::DeclConsumer consumer) const override; ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const override; SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, bool omitAssertions) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; }; /// Behavior specific to representing the Body of a NominalTypeDecl or /// ExtensionDecl scope class IterableTypeBodyPortion final : public Portion { public: IterableTypeBodyPortion() : Portion("Body") {} bool lookupMembersOf(const GenericTypeOrExtensionScope *scope, ASTScopeImpl::DeclConsumer consumer) const override; ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const override; SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, bool omitAssertions) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; }; /// GenericType or Extension scope /// : Whole type decl, trailing where clause, or body class GenericTypeOrExtensionScope : public ASTScopeImpl { public: const Portion *const portion; GenericTypeOrExtensionScope(ScopeKind kind, const Portion *p) : ASTScopeImpl(kind), portion(p) {} virtual ~GenericTypeOrExtensionScope() {} virtual NullablePtr getIterableDeclContext() const { return nullptr; } virtual bool shouldHaveABody() const { return false; } protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; public: virtual void expandBody(ScopeCreator &); virtual Decl *getDecl() const = 0; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; /// \c tryBindExtension needs to get the extended nominal, and the DeclContext /// is the parent of the \c ExtensionDecl. If the \c SourceRange of an \c /// ExtensionScope were to start where the \c ExtensionDecl says, the lookup /// source location would fall within the \c ExtensionScope. This inclusion /// would cause the lazy \c ExtensionScope to be expanded which would ask for /// its generic parameters in order to create those sub-scopes. That request /// would cause a cycle because it would ask for the extended nominal. So, /// move the source range of an \c ExtensionScope *past* the extended nominal /// type, which is not in-scope there anyway. virtual SourceRange moveStartPastExtendedNominal(SourceRange) const = 0; virtual GenericContext *getGenericContext() const = 0; virtual std::string declKindName() const = 0; virtual bool doesDeclHaveABody() const; const char *portionName() const { return portion->portionName; } std::string getClassName() const; public: // Only for DeclScope, not BodyScope // Returns the where clause scope, or the parent if none virtual ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &); virtual NullablePtr getCorrespondingNominalTypeDecl() const { return nullptr; } bool areMembersVisibleFromWhereClause() const; virtual void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) {} protected: bool lookupLocalsOrMembers(ASTScopeImpl::DeclConsumer consumer) const override; void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr getLookupLimit() const override; virtual NullablePtr getLookupLimitForDecl() const; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::NominalType || scope->getKind() == ScopeKind::Extension || scope->getKind() == ScopeKind::TypeAlias || scope->getKind() == ScopeKind::OpaqueType; } }; class GenericTypeScope : public GenericTypeOrExtensionScope { public: GenericTypeScope(ScopeKind kind, const Portion *p) : GenericTypeOrExtensionScope(kind, p) { } virtual ~GenericTypeScope() {} SourceRange moveStartPastExtendedNominal(SourceRange) const override; protected: NullablePtr genericParams() const override; }; class IterableTypeScope : public GenericTypeScope { public: IterableTypeScope(ScopeKind kind, const Portion *p) : GenericTypeScope(kind, p) {} virtual ~IterableTypeScope() {} virtual SourceRange getBraces() const = 0; bool shouldHaveABody() const override { return true; } bool doesDeclHaveABody() const override; void expandBody(ScopeCreator &) override; public: NullablePtr insertionPointForDeferredExpansion() override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::NominalType || scope->getKind() == ScopeKind::Extension; } }; class NominalTypeScope final : public IterableTypeScope { public: NominalTypeDecl *decl; NominalTypeScope(const Portion *p, NominalTypeDecl *e) : IterableTypeScope(ScopeKind::NominalType, p), decl(e) {} virtual ~NominalTypeScope() {} std::string declKindName() const override { return "NominalType"; } NullablePtr getIterableDeclContext() const override { return decl; } NullablePtr getCorrespondingNominalTypeDecl() const override { return decl; } GenericContext *getGenericContext() const override { return decl; } Decl *getDecl() const override { return decl; } SourceRange getBraces() const override; NullablePtr getLookupLimitForDecl() const override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::NominalType; } }; class ExtensionScope final : public IterableTypeScope { public: ExtensionDecl *const decl; ExtensionScope(const Portion *p, ExtensionDecl *e) : IterableTypeScope(ScopeKind::Extension, p), decl(e) {} virtual ~ExtensionScope() {} GenericContext *getGenericContext() const override { return decl; } NullablePtr getIterableDeclContext() const override { return decl; } NullablePtr getCorrespondingNominalTypeDecl() const override; std::string declKindName() const override { return "Extension"; } SourceRange getBraces() const override; SourceRange moveStartPastExtendedNominal(SourceRange) const override; ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; Decl *getDecl() const override { return decl; } NullablePtr getLookupLimitForDecl() const override; protected: NullablePtr genericParams() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::Extension; } }; class TypeAliasScope final : public GenericTypeScope { public: TypeAliasDecl *const decl; TypeAliasScope(const Portion *p, TypeAliasDecl *e) : GenericTypeScope(ScopeKind::TypeAlias, p), decl(e) {} virtual ~TypeAliasScope() {} std::string declKindName() const override { return "TypeAlias"; } ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; GenericContext *getGenericContext() const override { return decl; } Decl *getDecl() const override { return decl; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::TypeAlias; } }; class OpaqueTypeScope final : public GenericTypeScope { public: OpaqueTypeDecl *const decl; OpaqueTypeScope(const Portion *p, OpaqueTypeDecl *e) : GenericTypeScope(ScopeKind::OpaqueType, p), decl(e) {} virtual ~OpaqueTypeScope() {} std::string declKindName() const override { return "OpaqueType"; } GenericContext *getGenericContext() const override { return decl; } Decl *getDecl() const override { return decl; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::OpaqueType; } }; /// Since each generic parameter can "see" the preceding ones, /// (e.g. ) -- it's not legal but that's how lookup behaves -- /// Each GenericParamScope scopes just ONE parameter, and we next /// each one within the previous one. /// /// Here's a wrinkle: for a Subscript, the caller expects this scope (based on /// source loc) to match requested DeclContexts for starting lookup in EITHER /// the getter or setter AbstractFunctionDecl (context) class GenericParamScope final : public ASTScopeImpl { public: /// The declaration that has generic parameters. Decl *const holder; /// The generic parameters themselves. GenericParamList *const paramList; /// The index of the current parameter. const unsigned index; GenericParamScope(Decl *holder, GenericParamList *paramList, unsigned index) : ASTScopeImpl(ScopeKind::GenericParam), holder(holder), paramList(paramList), index(index) {} virtual ~GenericParamScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr addressForPrinting() const override { return paramList; } protected: bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::GenericParam; } }; /// Concrete class for a function/initializer/deinitializer class AbstractFunctionDeclScope final : public ASTScopeImpl { public: AbstractFunctionDecl *const decl; AbstractFunctionDeclScope(AbstractFunctionDecl *e) : ASTScopeImpl(ScopeKind::AbstractFunctionDecl), decl(e) {} virtual ~AbstractFunctionDeclScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: Decl *getDecl() const { return decl; } protected: NullablePtr genericParams() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::AbstractFunctionDecl; } }; /// The parameters for an abstract function (init/func/deinit)., subscript, and /// enum element class ParameterListScope final : public ASTScopeImpl { public: ParameterList *const params; /// For get functions in subscript declarations, /// a lookup into the subscript parameters must count as the get func context. const NullablePtr matchingContext; ParameterListScope(ParameterList *params, NullablePtr matchingContext) : ASTScopeImpl(ScopeKind::ParameterList), params(params), matchingContext(matchingContext) {} virtual ~ParameterListScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; NullablePtr addressForPrinting() const override { return params; } bool ignoreInDebugInfo() const override { return true; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ParameterList; } }; /// Body of functions, methods, constructors, destructors and accessors. class FunctionBodyScope : public ASTScopeImpl { public: AbstractFunctionDecl *const decl; FunctionBodyScope(AbstractFunctionDecl *e) : ASTScopeImpl(ScopeKind::FunctionBody), decl(e) {} virtual ~FunctionBodyScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); void expandBody(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Decl *getDecl() const { return decl; } bool ignoreInDebugInfo() const override { return true; } protected: bool lookupLocalsOrMembers(DeclConsumer) const override; public: NullablePtr insertionPointForDeferredExpansion() override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::FunctionBody; } }; class DefaultArgumentInitializerScope final : public ASTScopeImpl { public: ParamDecl *const decl; DefaultArgumentInitializerScope(ParamDecl *e) : ASTScopeImpl(ScopeKind::DefaultArgumentInitializer), decl(e) {} ~DefaultArgumentInitializerScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; public: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Decl *getDecl() const { return decl; } bool ignoreInDebugInfo() const override { return true; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::DefaultArgumentInitializer; } }; /// The scope for custom attributes and their arguments, such as for /// attached property wrappers and for attached macros. /// /// Source locations for the attribute name and its arguments are in the /// custom attribute, so lookup is invoked from within the attribute /// itself. class CustomAttributeScope final : public ASTScopeImpl { public: CustomAttr *attr; Decl *decl; CustomAttributeScope(CustomAttr *attr,Decl *decl) : ASTScopeImpl(ScopeKind::CustomAttribute), attr(attr), decl(decl) {} virtual ~CustomAttributeScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; NullablePtr addressForPrinting() const override { return decl; } bool ignoreInDebugInfo() const override { return true; } private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::CustomAttribute; } }; /// PatternBindingDecl's (PBDs) are tricky (See the comment for \c /// PatternBindingDecl): /// /// A PBD contains a list of "patterns", e.g. /// var (a, b) = foo(), (c,d) = bar() which has two patterns. /// /// For each pattern, there will be potentially three scopes: /// always one for the declarations, maybe one for the initializers, and maybe /// one for users of that pattern. /// /// If a PBD occurs in code, its initializer can access all prior declarations. /// Thus, a new scope must be created, nested in the scope of the PBD. /// In contrast, if a PBD occurs in a type declaration body, its initializer /// cannot access prior declarations in that body. /// /// As a further complication, we get VarDecls and their accessors in deferred /// which really must go into one of the PBD scopes. So we discard them in /// createIfNeeded, and special-case their creation in /// addVarDeclScopesAndTheirAccessors. class AbstractPatternEntryScope : public ASTScopeImpl { public: PatternBindingDecl *const decl; const unsigned patternEntryIndex; AbstractPatternEntryScope(ScopeKind kind, PatternBindingDecl *, unsigned entryIndex); virtual ~AbstractPatternEntryScope() {} const PatternBindingEntry &getPatternEntry() const; Pattern *getPattern() const; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: Decl *getDecl() const { return decl; } }; class PatternEntryDeclScope final : public AbstractPatternEntryScope { const bool isLocalBinding; std::optional endLoc; public: PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex, bool isLocalBinding, std::optional endLoc) : AbstractPatternEntryScope(ScopeKind::PatternEntryDecl, pbDecl, entryIndex), isLocalBinding(isLocalBinding), endLoc(endLoc) {} virtual ~PatternEntryDeclScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: bool lookupLocalsOrMembers(DeclConsumer) const override; bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::PatternEntryDecl; } }; class PatternEntryInitializerScope final : public AbstractPatternEntryScope { Expr *initAsWrittenWhenCreated; public: PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex) : AbstractPatternEntryScope(ScopeKind::PatternEntryInitializer, pbDecl, entryIndex), initAsWrittenWhenCreated(pbDecl->isDebuggerBinding() ? pbDecl->getInit(entryIndex) : pbDecl->getOriginalInit(entryIndex)) {} virtual ~PatternEntryInitializerScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; NullablePtr getLookupParent() const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: bool lookupLocalsOrMembers(DeclConsumer) const override; bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::PatternEntryInitializer; } }; /// The scope introduced by a conditional clause initializer in an /// if/while/guard statement. class ConditionalClauseInitializerScope final : public ASTScopeImpl { public: Expr *const initializer; const SourceRange bodyRange; ConditionalClauseInitializerScope(Expr *initializer) : ASTScopeImpl(ScopeKind::ConditionalClauseInitializer), initializer(initializer) {} virtual ~ConditionalClauseInitializerScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; NullablePtr getLookupParent() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ConditionalClauseInitializer; } }; /// If, while, & guard statements all start with a conditional clause, then some /// later part of the statement, (then, body, or after the guard) circumvents /// the normal lookup rule to pass the lookup scope into the deepest conditional /// clause. class ConditionalClausePatternUseScope final : public ASTScopeImpl { StmtConditionElement sec; SourceLoc endLoc; public: ConditionalClausePatternUseScope(StmtConditionElement sec, SourceLoc endLoc) : ASTScopeImpl(ScopeKind::ConditionalClausePatternUse), sec(sec), endLoc(endLoc) {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; bool lookupLocalsOrMembers(DeclConsumer) const override; void printSpecifics(llvm::raw_ostream &out) const override; bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ConditionalClausePatternUse; } }; /// Capture lists introduce local bindings. class CaptureListScope final : public ASTScopeImpl { public: CaptureListExpr *const expr; CaptureListScope(CaptureListExpr *e) : ASTScopeImpl(ScopeKind::CaptureList), expr(e) {} virtual ~CaptureListScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Expr *getExpr() const { return expr; } bool lookupLocalsOrMembers(DeclConsumer) const override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::CaptureList; } }; /// For a closure with named parameters, this scope does the local bindings. class ClosureParametersScope final : public ASTScopeImpl { public: AbstractClosureExpr *const closureExpr; ClosureParametersScope(AbstractClosureExpr *closureExpr) : ASTScopeImpl(ScopeKind::ClosureParameters), closureExpr(closureExpr) {} virtual ~ClosureParametersScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Expr *getExpr() const { return closureExpr; } bool ignoreInDebugInfo() const override { return true; } protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); protected: bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ClosureParameters; } }; class TopLevelCodeScope final : public ASTScopeImpl { public: TopLevelCodeDecl *const decl; SourceLoc endLoc; TopLevelCodeScope(TopLevelCodeDecl *e, SourceLoc endLoc) : ASTScopeImpl(ScopeKind::TopLevelCode), decl(e), endLoc(endLoc) {} virtual ~TopLevelCodeScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Decl *getDecl() const { return decl; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::TopLevelCode; } }; /// The \c _@specialize attribute. class SpecializeAttributeScope final : public ASTScopeImpl { public: SpecializeAttr *const specializeAttr; AbstractFunctionDecl *const whatWasSpecialized; SpecializeAttributeScope(SpecializeAttr *specializeAttr, AbstractFunctionDecl *whatWasSpecialized) : ASTScopeImpl(ScopeKind::SpecializeAttribute), specializeAttr(specializeAttr), whatWasSpecialized(whatWasSpecialized) { } virtual ~SpecializeAttributeScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; NullablePtr addressForPrinting() const override { return specializeAttr; } protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::SpecializeAttribute; } }; /// A `@differentiable` attribute scope. /// /// This exists because `@differentiable` attribute may have a `where` clause /// referring to generic parameters from some generic context. class DifferentiableAttributeScope final : public ASTScopeImpl { public: DifferentiableAttr *const differentiableAttr; Decl *const attributedDeclaration; DifferentiableAttributeScope(DifferentiableAttr *diffAttr, Decl *decl) : ASTScopeImpl(ScopeKind::DifferentiableAttribute), differentiableAttr(diffAttr), attributedDeclaration(decl) {} virtual ~DifferentiableAttributeScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; NullablePtr addressForPrinting() const override { return differentiableAttr; } protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::DifferentiableAttribute; } }; class SubscriptDeclScope final : public ASTScopeImpl { public: SubscriptDecl *const decl; SubscriptDeclScope(SubscriptDecl *e) : ASTScopeImpl(ScopeKind::SubscriptDecl), decl(e) {} virtual ~SubscriptDeclScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: Decl *getDecl() const { return decl; } protected: NullablePtr genericParams() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::SubscriptDecl; } }; class EnumElementScope : public ASTScopeImpl { EnumElementDecl *const decl; public: EnumElementScope(EnumElementDecl *e) : ASTScopeImpl(ScopeKind::EnumElement), decl(e) {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; ASTScopeImpl *expandSpecifically(ScopeCreator &) override; Decl *getDecl() const { return decl; } private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::EnumElement; } }; class MacroDeclScope final : public ASTScopeImpl { public: MacroDecl *const decl; MacroDeclScope(MacroDecl *e) : ASTScopeImpl(ScopeKind::MacroDecl), decl(e) {} virtual ~MacroDeclScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: Decl *getDecl() const { return decl; } protected: NullablePtr genericParams() const override; bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::MacroDecl; } }; /// The scope introduced for the definition of a macro, which follows the `=`. class MacroDefinitionScope final : public ASTScopeImpl { public: Expr *const definition; MacroDefinitionScope(Expr *definition) : ASTScopeImpl(ScopeKind::MacroDefinition), definition(definition) {} virtual ~MacroDefinitionScope() {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::MacroDefinition; } }; class MacroExpansionDeclScope final : public ASTScopeImpl { public: MacroExpansionDecl *const decl; MacroExpansionDeclScope(MacroExpansionDecl *e) : ASTScopeImpl(ScopeKind::MacroExpansionDecl), decl(e) {} virtual ~MacroExpansionDeclScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: Decl *getDecl() const { return decl; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::MacroExpansionDecl; } }; class AbstractStmtScope : public ASTScopeImpl { protected: AbstractStmtScope(ScopeKind kind) : ASTScopeImpl(kind) { } public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; virtual Stmt *getStmt() const = 0; protected: bool isLabeledStmtLookupTerminator() const override; }; class LabeledConditionalStmtScope : public AbstractStmtScope { protected: LabeledConditionalStmtScope(ScopeKind kind) : AbstractStmtScope(kind) { } public: Stmt *getStmt() const override; virtual LabeledConditionalStmt *getLabeledConditionalStmt() const = 0; protected: /// Return the lookupParent required to search these. ASTScopeImpl *createNestedConditionalClauseScopes(ScopeCreator &, SourceLoc); }; class IfStmtScope final : public LabeledConditionalStmtScope { public: IfStmt *const stmt; IfStmtScope(IfStmt *e) : LabeledConditionalStmtScope(ScopeKind::IfStmt), stmt(e) {} virtual ~IfStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: LabeledConditionalStmt *getLabeledConditionalStmt() const override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::IfStmt; } }; class WhileStmtScope final : public LabeledConditionalStmtScope { public: WhileStmt *const stmt; WhileStmtScope(WhileStmt *e) : LabeledConditionalStmtScope(ScopeKind::WhileStmt), stmt(e) {} virtual ~WhileStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: LabeledConditionalStmt *getLabeledConditionalStmt() const override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::WhileStmt; } }; class GuardStmtScope final : public LabeledConditionalStmtScope { public: GuardStmt *const stmt; SourceLoc endLoc; GuardStmtScope(GuardStmt *e, SourceLoc endLoc) : LabeledConditionalStmtScope(ScopeKind::GuardStmt), stmt(e), endLoc(endLoc) {} virtual ~GuardStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: LabeledConditionalStmt *getLabeledConditionalStmt() const override; SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::GuardStmt; } }; /// A scope for the body of a guard statement. Lookups from the body must /// skip the parent scopes for introducing pattern bindings, since they're /// not visible in the guard body, only after the body ends. class GuardStmtBodyScope final : public ASTScopeImpl { public: ASTScopeImpl *const lookupParent; BraceStmt *const body; GuardStmtBodyScope(ASTScopeImpl *lookupParent, BraceStmt *body) : ASTScopeImpl(ScopeKind::GuardStmtBody), lookupParent(lookupParent), body(body) {} SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; NullablePtr getLookupParent() const override { return lookupParent; } bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::GuardStmtBody; } }; class RepeatWhileScope final : public AbstractStmtScope { public: RepeatWhileStmt *const stmt; RepeatWhileScope(RepeatWhileStmt *e) : AbstractStmtScope(ScopeKind::RepeatWhile), stmt(e) {} virtual ~RepeatWhileScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::RepeatWhile; } }; class DoStmtScope final : public AbstractStmtScope { public: DoStmt *const stmt; DoStmtScope(DoStmt *e) : AbstractStmtScope(ScopeKind::DoStmt), stmt(e) {} virtual ~DoStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::DoStmt; } }; class DoCatchStmtScope final : public AbstractStmtScope { public: DoCatchStmt *const stmt; DoCatchStmtScope(DoCatchStmt *e) : AbstractStmtScope(ScopeKind::DoCatchStmt), stmt(e) {} virtual ~DoCatchStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::DoCatchStmt; } }; class SwitchStmtScope final : public AbstractStmtScope { public: SwitchStmt *const stmt; SwitchStmtScope(SwitchStmt *e) : AbstractStmtScope(ScopeKind::SwitchStmt), stmt(e) {} virtual ~SwitchStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::SwitchStmt; } }; class ForEachStmtScope final : public AbstractStmtScope { public: ForEachStmt *const stmt; ForEachStmtScope(ForEachStmt *e) : AbstractStmtScope(ScopeKind::ForEachStmt), stmt(e) {} virtual ~ForEachStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ForEachStmt; } }; class ForEachPatternScope final : public ASTScopeImpl { public: ForEachStmt *const stmt; ForEachPatternScope(ForEachStmt *e) : ASTScopeImpl(ScopeKind::ForEachPattern), stmt(e) {} virtual ~ForEachPatternScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: bool lookupLocalsOrMembers(DeclConsumer) const override; bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::ForEachPattern; } }; /// The parent scope for a 'case' statement, consisting of zero or more /// CaseLabelItemScopes, followed by a CaseStmtBodyScope. /// /// +------------------------------------------------------------------ /// | CaseStmtScope /// +------------------------------------------------------------------ /// | +--------------------------+ /// | | CaseLabelItemScope: | /// | +--------------------------+ /// | case .foo(let x, let y) where | condition(x, y), | /// | ^------^--------------------^--^ | /// | this guard expression sees first 'x'/'y' | /// | +--------------------------+ /// | /// | +--------------------------+ /// | | CaseLabelItemScope: | /// | +--------------------------+ /// | .foo(let x, let y) where | condition(x, y), | /// | ^------^--------------------^--^ | /// | this guard expression sees second 'x'/'y' | /// | +--------------------------+ /// | /// | .bar(let x, let y) /// | this case label item doesn't have a guard, so no /// | scope is created. /// | /// | +---------------------------------------------------------------- /// | | CaseStmtBodyScope: /// | +---------------------------------------------------------------- /// | | { /// | | ... x, y <-- body sees "joined" 'x'/'y' created by parser /// | | } /// | +---------------------------------------------------------------- /// | /// +------------------------------------------------------------------ class CaseStmtScope final : public AbstractStmtScope { public: CaseStmt *const stmt; CaseStmtScope(CaseStmt *e) : AbstractStmtScope(ScopeKind::CaseStmt), stmt(e) {} virtual ~CaseStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: Stmt *getStmt() const override { return stmt; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::CaseStmt; } }; /// The scope used for the guard expression in a case statement. Any /// variables bound by the case label item's pattern are visible in /// this scope. class CaseLabelItemScope final : public ASTScopeImpl { public: CaseLabelItem item; CaseLabelItemScope(const CaseLabelItem &item) : ASTScopeImpl(ScopeKind::CaseLabelItem), item(item) {} virtual ~CaseLabelItemScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: bool lookupLocalsOrMembers(ASTScopeImpl::DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::CaseLabelItem; } }; /// The scope used for the body of a 'case' statement. /// /// If the 'case' statement has multiple case label items, each label /// item's pattern must bind the same variables; the parser creates /// "fake" variables to represent the join of the variables bound by /// each pattern. /// /// These "fake" variables are visible in the 'case' statement body. class CaseStmtBodyScope final : public ASTScopeImpl { public: CaseStmt *const stmt; CaseStmtBodyScope(CaseStmt *e) : ASTScopeImpl(ScopeKind::CaseStmtBody), stmt(e) {} virtual ~CaseStmtBodyScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; protected: bool lookupLocalsOrMembers(ASTScopeImpl::DeclConsumer) const override; bool isLabeledStmtLookupTerminator() const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::CaseStmtBody; } }; class BraceStmtScope final : public AbstractStmtScope { BraceStmt *const stmt; /// Declarations which are in scope from the beginning of the statement. ArrayRef localFuncsAndTypes; /// Declarations that are normally in scope only after their /// definition. ArrayRef localVars; /// The end location for bindings introduced in this scope. This can /// extend past the actual end of the BraceStmt in top-level code, /// where every TopLevelCodeDecl introduces a new scope through the /// end of the buffer. SourceLoc endLoc; public: BraceStmtScope(BraceStmt *e, ArrayRef localFuncsAndTypes, ArrayRef localVars, SourceLoc endLoc) : AbstractStmtScope(ScopeKind::BraceStmt), stmt(e), localFuncsAndTypes(localFuncsAndTypes), localVars(localVars), endLoc(endLoc) {} virtual ~BraceStmtScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: AnnotatedInsertionPoint expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; NullablePtr parentClosureIfAny() const; // public?? BraceStmt *getStmt() const override { return stmt; } protected: bool lookupLocalsOrMembers(DeclConsumer) const override; public: static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::BraceStmt; } }; /// Describes a scope introduced by a try/try!/try? expression. class TryScope final : public ASTScopeImpl { public: AnyTryExpr *const expr; TryScope(AnyTryExpr *e) : ASTScopeImpl(ScopeKind::Try), expr(e) {} virtual ~TryScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); public: SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; Expr *getExpr() const { return expr; } static bool classof(const ASTScopeImpl *scope) { return scope->getKind() == ScopeKind::Try; } }; } // namespace ast_scope } // namespace swift #endif // SWIFT_AST_AST_SCOPE_H