//===--- 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. /// /// Invarients: /// 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/NameLookup.h" // for DeclVisibilityKind #include "swift/Basic/Compiler.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" 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; namespace ast_scope { class ASTScopeImpl; class GenericTypeOrExtensionScope; class IterableTypeScope; class TypeAliasScope; class StatementConditionElementPatternScope; class ScopeCreator; #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 { friend class ASTVisitorForScopeCreation; friend class Portion; friend class GenericTypeOrExtensionWholePortion; friend class NomExtDeclPortion; friend class GenericTypeOrExtensionWherePortion; friend class GenericTypeOrExtensionWherePortion; friend class IterableTypeBodyPortion; friend class ScopeCreator; #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: /// Always set by the constructor, so that when creating a child /// the parent chain is available. ASTScopeImpl *parent = nullptr; // null at the root /// Child scopes, sorted by source range. Children storedChildren; // Must be updated after last child is added and after last child's source // position is known Optional cachedSourceRange; // When ignoring ASTNodes in a scope, they still must count towards a scope's // source range. So include their ranges here SourceRange sourceRangeOfIgnoredASTNodes; #pragma mark - constructor / destructor public: ASTScopeImpl(){}; // 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; // Make vanilla new illegal for ASTScopes. void *operator new(size_t bytes) = delete; // Need this because have virtual destructors void operator delete(void *data) {} // Only allow allocation of scopes using the allocator of a particular source // file. void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { assert(Mem); return Mem; } #pragma mark - tree declarations protected: NullablePtr getParent() { return parent; } NullablePtr getParent() const { return parent; } const Children &getChildren() const { return storedChildren; } void addChild(ASTScopeImpl *child, ASTContext &); private: NullablePtr getPriorSibling() const; public: void postOrderDo(function_ref); #pragma mark - source ranges public: SourceRange getSourceRange(bool forDebugging = false) const; protected: SourceManager &getSourceManager() const; bool hasValidSourceRange() const; bool hasValidSourceRangeOfIgnoredASTNodes() const; bool verifySourceRange() const; bool precedesInSource(const ASTScopeImpl *) const; bool verifyThatChildrenAreContained() const; bool verifyThatThisNodeComeAfterItsPriorSibling() const; virtual Decl *getEnclosingAbstractFunctionOrSubscriptDecl() const; public: virtual NullablePtr getClosureIfClosureScope() const; private: SourceRange getUncachedSourceRange(bool forDebugging = false) const; public: // for PatternEntryDeclScope::expandMe void cacheSourceRange(); private: void clearSourceRangeCache(); void cacheSourceRangesOfSlice(); void clearCachedSourceRangesOfMeAndAncestors(); /// Even ASTNodes that do not form scopes must be included in a Scope's source /// range. Widen the source range of the receiver to include the (ignored) /// node. void widenSourceRangeForIgnoredASTNode(ASTNode); // InterpolatedStringLiteralExprs and EditorPlaceHolders respond to // getSourceRange with the starting point. But we might be asked to lookup an // identifer within one of them. So, find the real source range of them here. SourceRange getEffectiveSourceRange(ASTNode) const; /// Since source ranges are cached but depend on child ranges, /// when descendants are added, my and my ancestor ranges must be /// recalculated. void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref); public: // public for debugging virtual SourceRange getChildlessSourceRange() const = 0; #pragma mark common queries public: virtual ASTContext &getASTContext() const; virtual NullablePtr getDeclContext() const { return nullptr; }; virtual NullablePtr getDecl() const { return nullptr; }; #pragma mark - debugging and printing public: virtual const SourceFile *getSourceFile() const; virtual std::string getClassName() const = 0; /// 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: LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "only for use within the debugger"); void dumpOneScopeMapLocation(std::pair lineColumn) const; private: llvm::raw_ostream &verificationError() const; #pragma mark - Scope tree creation protected: /// expandScope me, sending deferred nodes to my descendants. /// Return the new scope into which to place decls, if any. virtual NullablePtr expandMe(ScopeCreator &); /// ExpandMe for scopes that do not split scopes by introducing decls. virtual void expandNonSplittingMe(ScopeCreator &); public: // Some nodes (VarDecls and Accessors) are created directly from // pattern scope code and should neither be deferred nor should // contribute to widenSourceRangeForIgnoredASTNode. // Closures and captures are also created directly but are // screened out because they are expressions. static bool isHandledSpeciallyByPatterns(const ASTNode n); virtual NullablePtr getEnclosingAbstractStorageDecl() const; #pragma mark - - creation queries protected: /// In other words, does this scope introduce a new definition bool doISplitAScope() const { // Before an abstract storage decl, the decl is inaccessible. // After an abstract storage decl, it is now accessible. return isThisAnAbstractStorageDecl(); } public: virtual bool isThisAnAbstractStorageDecl() const { return false; } #pragma mark - lookup public: using DeclConsumer = namelookup::AbstractASTScopeDeclConsumer &; /// Entry point into ASTScopeImpl-land for lookups static Optional unqualifiedLookup(SourceFile *, DeclName, SourceLoc, const DeclContext *startingContext, Optional isCascadingUse, DeclConsumer); #pragma mark - - lookup- starting point private: static const ASTScopeImpl *findStartingScopeForLookup(SourceFile *, const DeclName name, const SourceLoc where, const DeclContext *ctx); protected: virtual bool doesContextMatchStartingContext(const DeclContext *) const; protected: const ASTScopeImpl *findInnermostEnclosingScope(SourceLoc) const; private: NullablePtr findChildContaining(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. /// Return final value for isCascadingUse /// /// If the lookup depends on implicit self, selfDC is its context. /// (Names in extensions never depend on self.) /// /// Because a body scope nests in a generic param scope, etc, we might look in /// the self type twice. That's why we pass haveAlreadyLookedHere. /// /// Look in this scope. /// \p selfDC is the context for names dependent on dynamic self, /// \p limit is a scope into which lookup should not go, /// \p haveAlreadyLookedHere is a Decl whose generics and self type has /// already been searched, \p isCascadingUse indicates whether the lookup /// results will need a cascading dependency or not \p consumer is the object /// to which found decls are reported. Returns the isCascadingUse information. Optional lookup(NullablePtr selfDC, NullablePtr limit, NullablePtr haveAlreadyLookedHere, Optional isCascadingUse, DeclConsumer consumer) const; /// Same as lookup, but handles the steps to recurse into the parent scope. Optional lookupInParent(NullablePtr selfDC, NullablePtr limit, NullablePtr haveAlreadyLookedHere, Optional isCascadingUse, DeclConsumer) const; /// Return isDone and isCascadingUse std::pair> lookInGenericsAndSelfType(const NullablePtr selfDC, const Optional isCascadingUse, DeclConsumer consumer) const; virtual NullablePtr computeSelfDCForParent(NullablePtr) const; virtual std::pair> lookupInSelfType(NullablePtr selfDC, Optional, DeclConsumer) const; /// The default for anything that does not do the lookup. /// Returns isFinished and isCascadingUse static std::pair> dontLookupInSelfType(Optional isCascadingUse) { return {false, isCascadingUse}; } virtual bool lookInGenericParameters(Optional isCascadingUse, DeclConsumer) const; // Consume the generic parameters in the context and its outer contexts static bool lookInMyAndOuterGenericParameters(const GenericContext *, Optional isCascadingUse, DeclConsumer); NullablePtr parentIfNotChildOfTopScope() const { const auto *p = getParent().get(); return p->getParent().isNonNull() ? p : nullptr; } /// The tree is organized by source location and for most nodes this is also /// what obtaines 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 parent; } #pragma mark - - lookup- local bindings protected: virtual Optional resolveIsCascadingUseForThisScope(Optional) const; // A local binding is a basically a local variable defined in that very scope // It is not an instance variable or inherited type. /// Return true if consumer returns true virtual bool lookupLocalBindings(Optional, DeclConsumer) const; static bool lookupLocalBindingsInPattern(Pattern *p, Optional isCascadingUse, DeclVisibilityKind vis, 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. virtual NullablePtr getLookupLimit() const; NullablePtr ancestorWithDeclSatisfying(function_ref predicate) 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; /// The number of \c Decls in the \c SourceFile that were already seen. /// Since parsing can be interleaved with type-checking, on every /// lookup, look at creating scopes for any \c Decls beyond this number. int numberOfDeclsAlreadySeen = 0; ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator) : SF(SF), scopeCreator(scopeCreator) {} std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: virtual NullablePtr getDeclContext() const override { return NullablePtr(SF); } void addNewDeclsToTree(); const SourceFile *getSourceFile() const override; NullablePtr addressForPrinting() const override { return SF; } protected: void expandNonSplittingMe(ScopeCreator &) override; }; class Portion { public: const char *portionName; Portion(const char *n) : portionName(n) {} virtual ~Portion() {} // Make vanilla new illegal for ASTScopes. void *operator new(size_t bytes) = delete; // Need this because have virtual destructors void operator delete(void *data) {} // Only allow allocation of scopes using the allocator of a particular source // file. void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { assert(Mem); return Mem; } virtual void expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const {} virtual SourceRange getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope) const = 0; /// Returns isDone and isCascadingUse virtual std::pair> lookupInSelfTypeOf(const GenericTypeOrExtensionScope *scope, NullablePtr selfDC, const Optional isCascadingUse, ASTScopeImpl::DeclConsumer consumer) const; virtual NullablePtr getLookupLimitFor(const GenericTypeOrExtensionScope *) const; }; // For the whole Decl scope of a GenericType or an Extension class GenericTypeOrExtensionWholePortion : public Portion { public: GenericTypeOrExtensionWholePortion() : Portion("Decl") {} virtual ~GenericTypeOrExtensionWholePortion() {} // Just for TypeAlias void expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const override; SourceRange getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *) const override; NullablePtr getLookupLimitFor(const GenericTypeOrExtensionScope *) const override; }; /// GenericTypeOrExtension = GenericType or Extension class GenericTypeOrExtensionWhereOrBodyPortion : public Portion { public: GenericTypeOrExtensionWhereOrBodyPortion(const char *n) : Portion(n) {} virtual ~GenericTypeOrExtensionWhereOrBodyPortion() {} std::pair> lookupInSelfTypeOf(const GenericTypeOrExtensionScope *scope, NullablePtr selfDC, const Optional isCascadingUse, ASTScopeImpl::DeclConsumer consumer) const override; }; /// Behavior specific to representing the trailing where clause of a /// GenericTypeDecl or ExtensionDecl scope. class GenericTypeOrExtensionWherePortion : public GenericTypeOrExtensionWhereOrBodyPortion { public: GenericTypeOrExtensionWherePortion() : GenericTypeOrExtensionWhereOrBodyPortion("Where") {} SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *) const override; }; /// Behavior specific to representing the Body of a NominalTypeDecl or /// ExtensionDecl scope class IterableTypeBodyPortion final : public GenericTypeOrExtensionWhereOrBodyPortion { public: IterableTypeBodyPortion() : GenericTypeOrExtensionWhereOrBodyPortion("Body") {} void expandScope(GenericTypeOrExtensionScope *, ScopeCreator &) const override; SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *) const override; }; /// GenericType or Extension scope /// : Whole type decl, trailing where clause, or body class GenericTypeOrExtensionScope : public ASTScopeImpl { public: const Portion *const portion; GenericTypeOrExtensionScope(const Portion *p) : portion(p) {} virtual ~GenericTypeOrExtensionScope() {} virtual NullablePtr getIterableDeclContext() const { return nullptr; } virtual bool shouldHaveABody() const { return false; } void expandNonSplittingMe(ScopeCreator &) override; SourceRange getChildlessSourceRange() const override; std::pair> lookupInSelfType(NullablePtr selfDC, const Optional isCascadingUse, ASTScopeImpl::DeclConsumer consumer) const override; virtual GenericContext *getGenericContext() const = 0; std::string getClassName() const override; virtual std::string declKindName() const = 0; virtual bool doesDeclHaveABody() const; const char *portionName() const { return portion->portionName; } bool lookInGenericParameters(Optional isCascadingUse, DeclConsumer) const override; NullablePtr computeSelfDCForParent(NullablePtr) const override; Optional resolveIsCascadingUseForThisScope( Optional isCascadingUse) const override; // Only for DeclScope, not BodyScope virtual ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) { return parent; } NullablePtr getDeclContext() const override; virtual NullablePtr getCorrespondingNominalTypeDecl() const { return nullptr; } virtual void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) {} protected: void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr getLookupLimit() const override; virtual NullablePtr getLookupLimitForDecl() const; }; class IterableTypeScope : public GenericTypeOrExtensionScope { public: IterableTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {} virtual ~IterableTypeScope() {} virtual SourceRange getBraces() const = 0; bool shouldHaveABody() const override { return true; } bool doesDeclHaveABody() const override; }; class NominalTypeScope final : public IterableTypeScope { public: NominalTypeDecl *decl; NominalTypeScope(const Portion *p, NominalTypeDecl *e) : IterableTypeScope(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; } NullablePtr getDecl() const override { return decl; } SourceRange getBraces() const override; NullablePtr getLookupLimitForDecl() const override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; void createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; }; class ExtensionScope final : public IterableTypeScope { public: ExtensionDecl *const decl; ExtensionScope(const Portion *p, ExtensionDecl *e) : IterableTypeScope(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; void createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; NullablePtr getDecl() const override { return decl; } }; class TypeAliasScope final : public GenericTypeOrExtensionScope { public: TypeAliasDecl *const decl; TypeAliasScope(const Portion *p, TypeAliasDecl *e) : GenericTypeOrExtensionScope(p), decl(e) {} virtual ~TypeAliasScope() {} std::string declKindName() const override { return "TypeAlias"; } void createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; GenericContext *getGenericContext() const override { return decl; } NullablePtr getDecl() const override { return decl; } }; class OpaqueTypeScope final : public GenericTypeOrExtensionScope { public: OpaqueTypeDecl *const decl; OpaqueTypeScope(const Portion *p, OpaqueTypeDecl *e) : GenericTypeOrExtensionScope(p), decl(e) {} virtual ~OpaqueTypeScope() {} std::string declKindName() const override { return "OpaqueType"; } GenericContext *getGenericContext() const override { return decl; } NullablePtr getDecl() const override { return decl; } }; /// Since each generic parameter can "see" the preceeding 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) : holder(holder), paramList(paramList), index(index) {} virtual ~GenericParamScope() {} /// Actually holder is always a GenericContext, need to test if /// ProtocolDecl or SubscriptDecl but will refactor later. NullablePtr getDeclContext() const override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr getEnclosingAbstractStorageDecl() const override; NullablePtr addressForPrinting() const override { return paramList; } protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; bool doesContextMatchStartingContext(const DeclContext *) const override; Optional resolveIsCascadingUseForThisScope(Optional) const override; }; /// Concrete class for a function/initializer/deinitializer class AbstractFunctionDeclScope final : public ASTScopeImpl { public: AbstractFunctionDecl *const decl; AbstractFunctionDeclScope(AbstractFunctionDecl *e) : decl(e) {} virtual ~AbstractFunctionDeclScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: virtual NullablePtr getDeclContext() const override { return decl; } virtual NullablePtr getDecl() const override { return decl; } NullablePtr getEnclosingAbstractStorageDecl() const override; protected: Decl *getEnclosingAbstractFunctionOrSubscriptDecl() const override; bool lookInGenericParameters(Optional isCascadingUse, DeclConsumer) const override; Optional resolveIsCascadingUseForThisScope(Optional) const override; }; /// The parameters for an abstract function (init/func/deinit). class AbstractFunctionParamsScope 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; AbstractFunctionParamsScope(ParameterList *params, NullablePtr matchingContext) : params(params), matchingContext(matchingContext) {} virtual ~AbstractFunctionParamsScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override; NullablePtr getEnclosingAbstractStorageDecl() const override; NullablePtr addressForPrinting() const override { return params; } }; class AbstractFunctionBodyScope : public ASTScopeImpl { public: AbstractFunctionDecl *const decl; AbstractFunctionBodyScope(AbstractFunctionDecl *e) : decl(e) {} virtual ~AbstractFunctionBodyScope() {} void expandNonSplittingMe(ScopeCreator &) override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override { return decl; } virtual NullablePtr getDecl() const override { return decl; } protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; Optional resolveIsCascadingUseForThisScope(Optional) const override; }; /// Body of methods, functions in types. class MethodBodyScope final : public AbstractFunctionBodyScope { public: MethodBodyScope(AbstractFunctionDecl *e) : AbstractFunctionBodyScope(e) {} std::string getClassName() const override; protected: NullablePtr computeSelfDCForParent(NullablePtr) const override; }; /// Body of "pure" functions, functions without an implicit "self". class PureFunctionBodyScope final : public AbstractFunctionBodyScope { public: PureFunctionBodyScope(AbstractFunctionDecl *e) : AbstractFunctionBodyScope(e) {} std::string getClassName() const override; bool lookupLocalBindings(Optional, DeclConsumer consumer) const override; protected: NullablePtr computeSelfDCForParent(NullablePtr) const override; }; class DefaultArgumentInitializerScope final : public ASTScopeImpl { public: ParamDecl *const decl; DefaultArgumentInitializerScope(ParamDecl *e) : decl(e) {} ~DefaultArgumentInitializerScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override; virtual NullablePtr getDecl() const override { return decl; } protected: Optional resolveIsCascadingUseForThisScope(Optional) const override; }; // Consider: // @_propertyWrapper // struct WrapperWithInitialValue { // } // struct HasWrapper { // @WrapperWithInitialValue var y = 17 // } // Lookup has to be able to find the use of WrapperWithInitialValue, that's what // this scope is for. Because the source positions are screwy. class AttachedPropertyWrapperScope final : public ASTScopeImpl { public: VarDecl *const decl; AttachedPropertyWrapperScope(VarDecl *e) : decl(e) {} virtual ~AttachedPropertyWrapperScope() {} std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; NullablePtr addressForPrinting() const override { return decl; } virtual NullablePtr getDeclContext() const override; static SourceRange getCustomAttributesSourceRange(const VarDecl *); }; /// 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; const DeclVisibilityKind vis; AbstractPatternEntryScope(PatternBindingDecl *, unsigned entryIndex, DeclVisibilityKind); virtual ~AbstractPatternEntryScope() {} const PatternBindingEntry &getPatternEntry() const; Pattern *getPattern() const; protected: void printSpecifics(llvm::raw_ostream &out) const override; void forEachVarDeclWithExplicitAccessors( ScopeCreator &scopeCreator, bool dontRegisterAsDuplicate, function_ref foundOne) const; public: NullablePtr addressForPrinting() const override { return decl; } bool isLastEntry() const; }; class PatternEntryDeclScope final : public AbstractPatternEntryScope { public: PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex, DeclVisibilityKind vis) : AbstractPatternEntryScope(pbDecl, entryIndex, vis) {} virtual ~PatternEntryDeclScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; static bool isHandledSpecially(const ASTNode n); }; class PatternEntryInitializerScope final : public AbstractPatternEntryScope { public: PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex, DeclVisibilityKind vis) : AbstractPatternEntryScope(pbDecl, entryIndex, vis) {} virtual ~PatternEntryInitializerScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override; virtual NullablePtr getDecl() const override { return decl; } protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; NullablePtr computeSelfDCForParent(NullablePtr) const override; Optional resolveIsCascadingUseForThisScope(Optional) const override; }; class PatternEntryUseScope final : public AbstractPatternEntryScope { public: /// If valid, I must not start before this. /// Pattern won't tell me where the initializer really ends because it may end /// in an EditorPlaceholder or InterpolatedStringLiteral Those tokens can /// contain names to look up after their source locations. const SourceLoc initializerEnd; PatternEntryUseScope(PatternBindingDecl *pbDecl, unsigned entryIndex, DeclVisibilityKind vis, SourceLoc initializerEnd) : AbstractPatternEntryScope(pbDecl, entryIndex, vis), initializerEnd(initializerEnd) {} virtual ~PatternEntryUseScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; }; /// The scope introduced by a conditional clause in an if/guard/while /// statement. /// Since there may be more than one "let foo = ..." in (e.g.) an "if", /// we allocate a matrushka of these. class ConditionalClauseScope final : public ASTScopeImpl { public: LabeledConditionalStmt *const enclosingStmt; /// The index of the conditional clause. const unsigned index; /// The statement after the conditions: body or then. Stmt *const stmtAfterAllConditions; NullablePtr statementConditionElementPatternScope; ConditionalClauseScope(LabeledConditionalStmt *enclosingStmt, unsigned index, Stmt *stmtAfterAllConditions) : enclosingStmt(enclosingStmt), index(index), stmtAfterAllConditions(stmtAfterAllConditions) {} virtual ~ConditionalClauseScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr addressForPrinting() const override { return enclosingStmt; } void createSubtreeForCondition(ScopeCreator &); SourceLoc startLocAccordingToCondition() const; NullablePtr getStatementConditionElementPatternScope() const; SourceRange getChildlessSourceRange() const override; }; /// 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 ConditionalClauseUseScope final : public ASTScopeImpl { ASTScopeImpl *const lookupParent; const SourceLoc startLoc; public: ConditionalClauseUseScope(ASTScopeImpl *lookupParent, SourceLoc startLoc) : lookupParent(lookupParent), startLoc(startLoc) {} SourceRange getChildlessSourceRange() const override; std::string getClassName() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; NullablePtr getLookupParent() const override { return lookupParent; } }; /// Within a ConditionalClauseScope, there may be a pattern binding /// StmtConditionElement. If so, it splits the scope into two scopes: one /// containing the definitions and the other containing the initializer. We must /// split it because the initializer must not be in scope of the definitions: /// e.g.: if let a = a {} /// We need to be able to lookup either a and the second a must not bind to the /// first one. This scope represents the scope of the variable being /// initialized. class StatementConditionElementPatternScope final : public ASTScopeImpl { public: Pattern *const pattern; StatementConditionElementPatternScope(Pattern *e) : pattern(e) {} virtual ~StatementConditionElementPatternScope() {} std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: NullablePtr addressForPrinting() const override { return pattern; } protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; }; /// Capture lists may contain initializer expressions /// No local bindings here (other than closures in initializers); /// rather include these in the params or body local bindings class CaptureListScope final : public ASTScopeImpl { public: CaptureListExpr *const expr; CaptureListScope(CaptureListExpr *e) : expr(e) {} virtual ~CaptureListScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; NullablePtr addressForPrinting() const override { return expr; } virtual NullablePtr getDeclContext() const override; }; // In order for compatibility with existing lookup, closures are represented // by multiple scopes: An overall scope (including the part before the "in" // and a body scope, including the part after the "in" class AbstractClosureScope : public ASTScopeImpl { public: NullablePtr captureList; ClosureExpr *const closureExpr; AbstractClosureScope(ClosureExpr *closureExpr, NullablePtr captureList) : captureList(captureList), closureExpr(closureExpr) {} virtual ~AbstractClosureScope() {} NullablePtr getClosureIfClosureScope() const override; NullablePtr getDeclContext() const override { return closureExpr; } NullablePtr addressForPrinting() const override { return closureExpr; } }; class WholeClosureScope final : public AbstractClosureScope { public: WholeClosureScope(ClosureExpr *closureExpr, NullablePtr captureList) : AbstractClosureScope(closureExpr, captureList) {} virtual ~WholeClosureScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; }; /// For a closure with named parameters, this scope does the local bindings. /// Absent if no "in". class ClosureParametersScope final : public AbstractClosureScope { public: ClosureParametersScope(ClosureExpr *closureExpr, NullablePtr captureList) : AbstractClosureScope(closureExpr, captureList) {} virtual ~ClosureParametersScope() {} std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; Optional resolveIsCascadingUseForThisScope( Optional isCascadingUse) const override; }; // The body encompasses the code in the closure; the part after the "in" if // there is an "in" class ClosureBodyScope final : public AbstractClosureScope { public: ClosureBodyScope(ClosureExpr *closureExpr, NullablePtr captureList) : AbstractClosureScope(closureExpr, captureList) {} virtual ~ClosureBodyScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: Optional resolveIsCascadingUseForThisScope( Optional isCascadingUse) const override; }; class TopLevelCodeScope final : public ASTScopeImpl { public: TopLevelCodeDecl *const decl; TopLevelCodeScope(TopLevelCodeDecl *e) : decl(e) {} virtual ~TopLevelCodeScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override { return decl; } virtual NullablePtr getDecl() const override { return decl; } }; /// The \c _@specialize attribute. class SpecializeAttributeScope final : public ASTScopeImpl { public: SpecializeAttr *const specializeAttr; AbstractFunctionDecl *const whatWasSpecialized; SpecializeAttributeScope(SpecializeAttr *specializeAttr, AbstractFunctionDecl *whatWasSpecialized) : specializeAttr(specializeAttr), whatWasSpecialized(whatWasSpecialized) { } virtual ~SpecializeAttributeScope() {} std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; NullablePtr addressForPrinting() const override { return specializeAttr; } NullablePtr getEnclosingAbstractStorageDecl() const override; protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; }; class SubscriptDeclScope final : public ASTScopeImpl { public: SubscriptDecl *const decl; SubscriptDeclScope(SubscriptDecl *e) : decl(e) {} virtual ~SubscriptDeclScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: virtual NullablePtr getDeclContext() const override { return decl; } virtual NullablePtr getDecl() const override { return decl; } protected: Decl *getEnclosingAbstractFunctionOrSubscriptDecl() const override; bool lookInGenericParameters(Optional isCascadingUse, DeclConsumer) const override; NullablePtr getEnclosingAbstractStorageDecl() const override { return decl; } public: bool isThisAnAbstractStorageDecl() const override { return true; } }; class VarDeclScope final : public ASTScopeImpl { public: VarDecl *const decl; VarDeclScope(VarDecl *e) : decl(e) {} virtual ~VarDeclScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; protected: void printSpecifics(llvm::raw_ostream &out) const override; public: virtual NullablePtr getDecl() const override { return decl; } NullablePtr getEnclosingAbstractStorageDecl() const override { return decl; } bool isThisAnAbstractStorageDecl() const override { return true; } }; class AbstractStmtScope : public ASTScopeImpl { public: virtual Stmt *getStmt() const = 0; NullablePtr addressForPrinting() const override { return getStmt(); } SourceRange getChildlessSourceRange() const override; }; class LabeledConditionalStmtScope : public AbstractStmtScope { public: Stmt *getStmt() const override; virtual LabeledConditionalStmt *getLabeledConditionalStmt() const = 0; /// If a condition is present, create the martuska. /// Return the lookupParent for the use scope. ASTScopeImpl *createCondScopes(); protected: /// Return the lookupParent required to search these. ASTScopeImpl *createCondScopes(ScopeCreator &); virtual Stmt *getStmtAfterTheConditions() const = 0; }; class IfStmtScope final : public LabeledConditionalStmtScope { public: IfStmt *const stmt; IfStmtScope(IfStmt *e) : stmt(e) {} virtual ~IfStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; LabeledConditionalStmt *getLabeledConditionalStmt() const override; protected: Stmt *getStmtAfterTheConditions() const override; }; class WhileStmtScope final : public LabeledConditionalStmtScope { public: WhileStmt *const stmt; WhileStmtScope(WhileStmt *e) : stmt(e) {} virtual ~WhileStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; LabeledConditionalStmt *getLabeledConditionalStmt() const override; protected: Stmt *getStmtAfterTheConditions() const override; }; class GuardStmtScope final : public LabeledConditionalStmtScope { public: GuardStmt *const stmt; GuardStmtScope(GuardStmt *e) : stmt(e) {} virtual ~GuardStmtScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; LabeledConditionalStmt *getLabeledConditionalStmt() const override; protected: Stmt *getStmtAfterTheConditions() const override; }; class RepeatWhileScope final : public AbstractStmtScope { public: RepeatWhileStmt *const stmt; RepeatWhileScope(RepeatWhileStmt *e) : stmt(e) {} virtual ~RepeatWhileScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; Stmt *getStmt() const override { return stmt; } }; class DoCatchStmtScope final : public AbstractStmtScope { public: DoCatchStmt *const stmt; DoCatchStmtScope(DoCatchStmt *e) : stmt(e) {} virtual ~DoCatchStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; Stmt *getStmt() const override { return stmt; } }; class SwitchStmtScope final : public AbstractStmtScope { public: SwitchStmt *const stmt; SwitchStmtScope(SwitchStmt *e) : stmt(e) {} virtual ~SwitchStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; Stmt *getStmt() const override { return stmt; } }; class ForEachStmtScope final : public AbstractStmtScope { public: ForEachStmt *const stmt; ForEachStmtScope(ForEachStmt *e) : stmt(e) {} virtual ~ForEachStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; Stmt *getStmt() const override { return stmt; } }; class ForEachPatternScope final : public AbstractStmtScope { public: ForEachStmt *const stmt; ForEachPatternScope(ForEachStmt *e) : stmt(e) {} virtual ~ForEachPatternScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; Stmt *getStmt() const override { return stmt; } SourceRange getChildlessSourceRange() const override; protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; }; class CatchStmtScope final : public AbstractStmtScope { public: CatchStmt *const stmt; CatchStmtScope(CatchStmt *e) : stmt(e) {} virtual ~CatchStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; Stmt *getStmt() const override { return stmt; } protected: bool lookupLocalBindings(Optional, ASTScopeImpl::DeclConsumer) const override; }; class CaseStmtScope final : public AbstractStmtScope { public: CaseStmt *const stmt; CaseStmtScope(CaseStmt *e) : stmt(e) {} virtual ~CaseStmtScope() {} void expandNonSplittingMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; Stmt *getStmt() const override { return stmt; } protected: bool lookupLocalBindings(Optional, ASTScopeImpl::DeclConsumer) const override; }; class BraceStmtScope final : public AbstractStmtScope { public: BraceStmt *const stmt; BraceStmtScope(BraceStmt *e) : stmt(e) {} virtual ~BraceStmtScope() {} NullablePtr expandMe(ScopeCreator &) override; std::string getClassName() const override; SourceRange getChildlessSourceRange() const override; virtual NullablePtr getDeclContext() const override; NullablePtr parentClosureIfAny() const; // public?? Stmt *getStmt() const override { return stmt; } protected: bool lookupLocalBindings(Optional, DeclConsumer) const override; }; } // namespace ast_scope } // namespace swift #endif // SWIFT_AST_AST_SCOPE_H