blob: 7a6bc43b825c530c6bafe40d15f32d67f748147c [file] [log] [blame]
//===--- 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/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"
/// 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 \
" Try compiling with '-disable-astscope-lookup'.")
#define ASTScope_unreachable(message) \
llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.")
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 ast_scope {
class ASTScopeImpl;
class GenericTypeOrExtensionScope;
class IterableTypeScope;
class TypeAliasScope;
class ScopeCreator;
struct AnnotatedInsertionPoint {
ASTScopeImpl *insertionPoint;
const char *explanation;
};
#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 NodeAdder;
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<ASTScopeImpl *, 4>;
/// 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.
/// Must clear source range change whenever this changes
Children storedChildren;
bool wasExpanded = false;
/// For use-before-def, ASTAncestor scopes may be added to a BraceStmt.
unsigned astAncestorScopeCount = 0;
/// Can clear storedChildren, so must remember this
bool haveAddedCleanup = false;
// Must be updated after last child is added and after last child's source
// position is known
mutable Optional<SourceRange> 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) {
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
#pragma mark - tree declarations
protected:
NullablePtr<ASTScopeImpl> getParent() { return parent; }
NullablePtr<const ASTScopeImpl> getParent() const { return parent; }
const Children &getChildren() const { return storedChildren; }
/// Get ride of descendants and remove them from scopedNodes so the scopes
/// can be recreated. Needed because typechecking inserts a return statment
/// into intiailizers.
void disownDescendants(ScopeCreator &);
public: // for addReusedBodyScopes
void addChild(ASTScopeImpl *child, ASTContext &);
std::vector<ASTScopeImpl *> rescueASTAncestorScopesForReuseFromMe();
/// When reexpanding, do we always create a new body?
virtual NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued();
std::vector<ASTScopeImpl *>
rescueASTAncestorScopesForReuseFromMeOrDescendants();
void replaceASTAncestorScopes(ArrayRef<ASTScopeImpl *>);
private:
void removeChildren();
private:
void emancipate() { parent = nullptr; }
NullablePtr<ASTScopeImpl> getPriorSibling() const;
public:
void preOrderDo(function_ref<void(ASTScopeImpl *)>);
/// Like preorderDo but without myself.
void preOrderChildrenDo(function_ref<void(ASTScopeImpl *)>);
void postOrderDo(function_ref<void(ASTScopeImpl *)>);
#pragma mark - source ranges
#pragma mark - source range queries
public:
SourceRange getSourceRangeOfScope(bool omitAssertions = false) const;
/// 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;
void computeAndCacheSourceRangeOfScope(bool omitAssertions = false) const;
bool isSourceRangeCached(bool omitAssertions = false) const;
bool checkSourceRangeOfThisASTNode() const;
/// For debugging
bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "",
StringRef className = "");
unsigned countDescendants() const;
/// Make sure that when the argument is executed, there are as many
/// descendants after as before.
void assertThatTreeDoesNotShrink(function_ref<void()>);
private:
SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const;
SourceRange
computeSourceRangeOfScopeWithChildASTNodes(bool omitAssertions = false) const;
bool ensureNoAncestorsSourceRangeIsCached() const;
#pragma mark - source range adjustments
private:
SourceRange widenSourceRangeForIgnoredASTNodes(SourceRange range) const;
/// If the scope refers to a Decl whose source range tells the whole story,
/// for example a NominalTypeScope, it is not necessary to widen the source
/// range by examining the children. In that case we could just return
/// the childlessRange here.
/// But, we have not marked such scopes yet. Doing so would be an
/// optimization.
SourceRange widenSourceRangeForChildren(SourceRange range,
bool omitAssertions) const;
/// 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);
private:
void clearCachedSourceRangesOfMeAndAncestors();
public:
/// 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<void()>);
public: // public for debugging
/// Returns source range of this node alone, without factoring in any
/// children.
virtual SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0;
protected:
SourceManager &getSourceManager() const;
bool hasValidSourceRange() const;
bool hasValidSourceRangeOfIgnoredASTNodes() const;
bool precedesInSource(const ASTScopeImpl *) const;
bool verifyThatChildrenAreContainedWithin(SourceRange) const;
bool verifyThatThisNodeComeAfterItsPriorSibling() const;
virtual SourceRange
getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const;
private:
bool checkSourceRangeAfterExpansion(const ASTContext &) const;
#pragma mark common queries
public:
virtual NullablePtr<ClosureExpr> getClosureIfClosureScope() const;
virtual ASTContext &getASTContext() const;
virtual NullablePtr<DeclContext> getDeclContext() const;
virtual NullablePtr<Decl> getDeclIfAny() const { return nullptr; };
virtual NullablePtr<Stmt> getStmtIfAny() const { return nullptr; };
virtual NullablePtr<Expr> getExprIfAny() const { return nullptr; };
virtual NullablePtr<DeclAttribute> getDeclAttributeIfAny() const {
return nullptr;
}
virtual NullablePtr<const void> getReferrent() 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<const void> addressForPrinting() const;
public:
LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
"only for use within the debugger");
void dumpOneScopeMapLocation(std::pair<unsigned, unsigned> lineColumn);
private:
llvm::raw_ostream &verificationError() const;
#pragma mark - Scope tree creation
public:
/// expandScope me, sending deferred nodes to my descendants.
/// Return the scope into which to place subsequent decls
ASTScopeImpl *expandAndBeCurrent(ScopeCreator &);
unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; }
bool getWasExpanded() const { return wasExpanded; }
protected:
void resetASTAncestorScopeCount() { astAncestorScopeCount = 0; }
void increaseASTAncestorScopeCount(unsigned c) { astAncestorScopeCount += c; }
void setWasExpanded() { wasExpanded = true; }
virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0;
virtual void beCurrent();
bool isCurrent() const;
virtual bool isCurrentIfWasExpanded() const;
private:
/// Compare the pre-expasion range with the post-expansion range and return
/// false if lazyiness couild miss lookups.
bool checkLazySourceRange(const ASTContext &) const;
public:
/// Some scopes can be expanded lazily.
/// Such scopes must: not change their source ranges after expansion, and
/// their expansion must return an insertion point outside themselves.
/// After a node is expanded, its source range (getSourceRangeofThisASTNode
/// union children's ranges) must be same as this.
virtual NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion();
virtual SourceRange sourceRangeForDeferredExpansion() const;
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<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const;
bool isATypeDeclScope() const;
/// There are several places in the compiler that mutate the AST after the
/// fact, above and beyond adding Decls to the SourceFile. These are
/// documented in: rdar://53018839, rdar://53027266, rdar://53027733,
/// rdar://53028050
/// Return true if did reexpand
bool reexpandIfObsolete(ScopeCreator &);
private:
void reexpand(ScopeCreator &);
virtual ScopeCreator &getScopeCreator();
#pragma mark - - creation queries
public:
virtual bool isThisAnAbstractStorageDecl() const { return false; }
#pragma mark - lookup
public:
using DeclConsumer = namelookup::AbstractASTScopeDeclConsumer &;
/// Entry point into ASTScopeImpl-land for lookups
static llvm::SmallVector<const ASTScopeImpl *, 0>
unqualifiedLookup(SourceFile *, DeclName, SourceLoc,
const DeclContext *startingContext, DeclConsumer);
static Optional<bool>
computeIsCascadingUse(ArrayRef<const ASTScopeImpl *> history,
Optional<bool> initialIsCascadingUse);
#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:
/// Not const because may reexpand some scopes.
const ASTScopeImpl *findInnermostEnclosingScope(SourceLoc,
NullablePtr<raw_ostream>);
const ASTScopeImpl *findInnermostEnclosingScopeImpl(SourceLoc,
NullablePtr<raw_ostream>,
SourceManager &,
ScopeCreator &);
private:
NullablePtr<ASTScopeImpl> 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.)
///
/// 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<T> { \code typealias T = Int; func foo (t :
/// T) {} \code } \code ShadowingGenericParameter<String>().foo(t: "hi")
///
/// So keep track of the last generic param list searched to avoid
/// duplicating work.
///
/// Look in this scope.
/// \param history are the scopes traversed for this lookup (including this
/// one) \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(llvm::SmallVectorImpl<const ASTScopeImpl *> &history,
NullablePtr<const ASTScopeImpl> limit,
NullablePtr<const GenericParamList> lastListSearched,
DeclConsumer consumer) const;
public:
/// Returns the SelfDC for parent (and possibly ancestor) scopes.
/// A return of None indicates that the previous child (in history) should be
/// asked.
virtual Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const;
protected:
/// Find either locals or members (no scope has both)
/// \param history The scopes visited since the start of lookup (including
/// this one)
/// \return True if lookup is done
virtual bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *> history,
DeclConsumer consumer) const;
/// Returns isDone and the list searched, if any
std::pair<bool, NullablePtr<const GenericParamList>>
lookInMyGenericParameters(
NullablePtr<const GenericParamList> priorListSearched,
DeclConsumer consumer) const;
virtual NullablePtr<const GenericParamList> genericParams() const;
// Consume the generic parameters in the context and its outer contexts
static bool lookInGenericParametersOf(NullablePtr<const GenericParamList>,
DeclConsumer);
NullablePtr<const ASTScopeImpl> 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<const ASTScopeImpl> getLookupParent() const {
return parent;
}
#pragma mark - - lookup- local bindings
protected:
virtual Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) const;
// 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(Pattern *p,
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.
///
/// 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<const ASTScopeImpl> getLookupLimit() const;
NullablePtr<const ASTScopeImpl>
ancestorWithDeclSatisfying(function_ref<bool(const Decl *)> 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;
ASTScopeImpl *insertionPoint;
/// 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.
/// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded
int numberOfDeclsAlreadySeen = 0;
ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator);
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
void printSpecifics(llvm::raw_ostream &out) const override;
public:
NullablePtr<DeclContext> getDeclContext() const override;
void addNewDeclsToScopeTree();
void buildFullyExpandedTree();
void
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
const SourceFile *getSourceFile() const override;
NullablePtr<const void> addressForPrinting() const override { return SF; }
bool crossCheckWithAST();
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
ScopeCreator &getScopeCreator() override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
};
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) {
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
/// Return the new insertion point
virtual ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
ScopeCreator &) const = 0;
virtual SourceRange
getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *scope,
bool omitAssertions) const = 0;
/// Returns isDone and isCascadingUse
virtual bool lookupMembersOf(const GenericTypeOrExtensionScope *scope,
ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer consumer) const;
virtual NullablePtr<const ASTScopeImpl>
getLookupLimitFor(const GenericTypeOrExtensionScope *) const;
virtual const Decl *
getReferrentOfScope(const GenericTypeOrExtensionScope *s) const;
virtual void beCurrent(IterableTypeScope *) const = 0;
virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0;
virtual NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const = 0;
virtual SourceRange
sourceRangeForDeferredExpansion(const 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<const ASTScopeImpl>
getLookupLimitFor(const GenericTypeOrExtensionScope *) const override;
const Decl *
getReferrentOfScope(const GenericTypeOrExtensionScope *s) const override;
/// Make whole portion lazy to avoid circularity in lookup of generic
/// parameters of extensions. When \c bindExtension is called, it needs to
/// unqualifed-lookup the type being extended. That causes an \c
/// ExtensionScope
/// (\c GenericTypeOrExtensionWholePortion) to be built.
/// The building process needs the generic parameters, but that results in a
/// request for the extended nominal type of the \c ExtensionDecl, which is
/// an endless recursion. Although we only need to make \c ExtensionScope
/// lazy, might as well do it for all \c IterableTypeScopes.
void beCurrent(IterableTypeScope *) const override;
bool isCurrentIfWasExpanded(const IterableTypeScope *) const override;
NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
SourceRange
sourceRangeForDeferredExpansion(const IterableTypeScope *) const override;
};
/// GenericTypeOrExtension = GenericType or Extension
class GenericTypeOrExtensionWhereOrBodyPortion : public Portion {
public:
GenericTypeOrExtensionWhereOrBodyPortion(const char *n) : Portion(n) {}
virtual ~GenericTypeOrExtensionWhereOrBodyPortion() {}
bool lookupMembersOf(const GenericTypeOrExtensionScope *scope,
ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer consumer) const override;
private:
/// A client needs to know if a lookup result required the dynamic implicit
/// self value. It is required if the lookup originates from a method body
/// or a lazy pattern initializer. So, one approach would be to call the
/// consumer to find members right from those scopes. However, because
/// members aren't the first things searched, generics are, that approache
/// ends up duplicating code from the \c GenericTypeOrExtensionScope. So we
/// take the approach of doing those lookups there, and using this function
/// to compute the selfDC from the history.
static NullablePtr<DeclContext>
computeSelfDC(ArrayRef<const ASTScopeImpl *> history);
};
/// Behavior specific to representing the trailing where clause of a
/// GenericTypeDecl or ExtensionDecl scope.
class GenericTypeOrExtensionWherePortion final
: public GenericTypeOrExtensionWhereOrBodyPortion {
public:
GenericTypeOrExtensionWherePortion()
: GenericTypeOrExtensionWhereOrBodyPortion("Where") {}
ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
ScopeCreator &) const override;
SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *,
bool omitAssertions) const override;
void beCurrent(IterableTypeScope *) const override;
bool isCurrentIfWasExpanded(const IterableTypeScope *) const override;
NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
SourceRange
sourceRangeForDeferredExpansion(const IterableTypeScope *) const override;
};
/// Behavior specific to representing the Body of a NominalTypeDecl or
/// ExtensionDecl scope
class IterableTypeBodyPortion final
: public GenericTypeOrExtensionWhereOrBodyPortion {
public:
IterableTypeBodyPortion()
: GenericTypeOrExtensionWhereOrBodyPortion("Body") {}
ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
ScopeCreator &) const override;
SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *,
bool omitAssertions) const override;
void beCurrent(IterableTypeScope *) const override;
bool isCurrentIfWasExpanded(const IterableTypeScope *) const override;
NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
SourceRange
sourceRangeForDeferredExpansion(const 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(const Portion *p) : portion(p) {}
virtual ~GenericTypeOrExtensionScope() {}
virtual NullablePtr<IterableDeclContext> 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;
NullablePtr<Decl> getDeclIfAny() const override { return getDecl(); }
NullablePtr<const void> getReferrent() const override;
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 locaiton 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;
std::string getClassName() const override;
virtual std::string declKindName() const = 0;
virtual bool doesDeclHaveABody() const;
const char *portionName() const { return portion->portionName; }
Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const override;
protected:
Optional<bool> resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const override;
public:
// Only for DeclScope, not BodyScope
// Returns the where clause scope, or the parent if none
virtual ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent,
ScopeCreator &);
NullablePtr<DeclContext> getDeclContext() const override;
virtual NullablePtr<NominalTypeDecl> getCorrespondingNominalTypeDecl() const {
return nullptr;
}
virtual void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) {}
protected:
bool
lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *> history,
ASTScopeImpl::DeclConsumer consumer) const override;
void printSpecifics(llvm::raw_ostream &out) const override;
public:
NullablePtr<const ASTScopeImpl> getLookupLimit() const override;
virtual NullablePtr<const ASTScopeImpl> getLookupLimitForDecl() const;
};
class GenericTypeScope : public GenericTypeOrExtensionScope {
public:
GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {}
virtual ~GenericTypeScope() {}
SourceRange moveStartPastExtendedNominal(SourceRange) const override;
protected:
NullablePtr<const GenericParamList> genericParams() const override;
};
class IterableTypeScope : public GenericTypeScope {
/// Because of \c parseDelayedDecl members can get added after the tree is
/// constructed, and they can be out of order. Detect this happening by
/// remembering the member count.
unsigned memberCount = 0;
public:
IterableTypeScope(const Portion *p) : GenericTypeScope(p) {}
virtual ~IterableTypeScope() {}
virtual SourceRange getBraces() const = 0;
bool shouldHaveABody() const override { return true; }
bool doesDeclHaveABody() const override;
void expandBody(ScopeCreator &) override;
protected:
void beCurrent() override;
bool isCurrentIfWasExpanded() const override;
public:
void makeWholeCurrent();
bool isWholeCurrent() const;
void makeBodyCurrent();
bool isBodyCurrent() const;
NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override;
SourceRange sourceRangeForDeferredExpansion() const override;
void countBodies(ScopeCreator &) const;
};
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<IterableDeclContext> getIterableDeclContext() const override {
return decl;
}
NullablePtr<NominalTypeDecl>
getCorrespondingNominalTypeDecl() const override {
return decl;
}
GenericContext *getGenericContext() const override { return decl; }
Decl *getDecl() const override { return decl; }
SourceRange getBraces() const override;
NullablePtr<const ASTScopeImpl> getLookupLimitForDecl() const override;
void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override;
ASTScopeImpl *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<IterableDeclContext> getIterableDeclContext() const override {
return decl;
}
NullablePtr<NominalTypeDecl> 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<const ASTScopeImpl> getLookupLimitForDecl() const override;
protected:
NullablePtr<const GenericParamList> genericParams() const override;
};
class TypeAliasScope final : public GenericTypeScope {
public:
TypeAliasDecl *const decl;
TypeAliasScope(const Portion *p, TypeAliasDecl *e)
: GenericTypeScope(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; }
};
class OpaqueTypeScope final : public GenericTypeScope {
public:
OpaqueTypeDecl *const decl;
OpaqueTypeScope(const Portion *p, OpaqueTypeDecl *e)
: GenericTypeScope(p), decl(e) {}
virtual ~OpaqueTypeScope() {}
std::string declKindName() const override { return "OpaqueType"; }
GenericContext *getGenericContext() const override { return decl; }
Decl *getDecl() const override { return decl; }
};
/// Since each generic parameter can "see" the preceeding ones,
/// (e.g. <A, B: A>) -- 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<DeclContext> getDeclContext() const override;
NullablePtr<const void> getReferrent() const override;
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
void printSpecifics(llvm::raw_ostream &out) const override;
public:
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override;
NullablePtr<const void> addressForPrinting() const override {
return paramList;
}
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
bool doesContextMatchStartingContext(const DeclContext *) const override;
Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) 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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
void printSpecifics(llvm::raw_ostream &out) const override;
public:
virtual NullablePtr<DeclContext> getDeclContext() const override;
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override;
NullablePtr<const void> getReferrent() const override;
static bool shouldCreateAccessorScope(const AccessorDecl *);
protected:
SourceRange
getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override;
private:
static SourceLoc getParmsSourceLocOfAFD(AbstractFunctionDecl *);
protected:
NullablePtr<const GenericParamList> genericParams() const override;
Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) const override;
};
/// 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<DeclContext> matchingContext;
ParameterListScope(ParameterList *params,
NullablePtr<DeclContext> matchingContext)
: params(params), matchingContext(matchingContext) {}
virtual ~ParameterListScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
SourceLoc fixupEndForBadInput(SourceRange) const;
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override;
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override;
NullablePtr<const void> addressForPrinting() const override { return params; }
};
class AbstractFunctionBodyScope : public ASTScopeImpl {
public:
AbstractFunctionDecl *const decl;
/// \c Parser::parseAbstractFunctionBodyDelayed can call \c
/// AbstractFunctionDecl::setBody after the tree has been constructed. So if
/// this changes, have to rebuild body.
NullablePtr<BraceStmt> bodyWhenLastExpanded;
AbstractFunctionBodyScope(AbstractFunctionDecl *e) : decl(e) {}
virtual ~AbstractFunctionBodyScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrentIfWasExpanded() const override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
void expandBody(ScopeCreator &);
public:
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override {
return decl;
}
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
static bool isAMethod(const AbstractFunctionDecl *);
NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) const override;
public:
NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override;
SourceRange sourceRangeForDeferredExpansion() const override;
};
/// Body of methods, functions in types.
class MethodBodyScope final : public AbstractFunctionBodyScope {
public:
MethodBodyScope(AbstractFunctionDecl *e) : AbstractFunctionBodyScope(e) {}
std::string getClassName() const override;
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const override;
Optional<NullablePtr<DeclContext>> computeSelfDCForParent() 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 lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const override;
};
class DefaultArgumentInitializerScope final : public ASTScopeImpl {
public:
ParamDecl *const decl;
DefaultArgumentInitializerScope(ParamDecl *e) : decl(e) {}
~DefaultArgumentInitializerScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
public:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override;
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
protected:
Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) 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;
/// Because we have to avoid request cycles, we approximate the test for an
/// AttachedPropertyWrapper with one based on source location. We might get
/// false positives, that that doesn't hurt anything. However, the result of
/// the conservative source range computation doesn't seem to be stable. So
/// keep the original here, and use it for source range queries.
/// rdar://55263708
const SourceRange sourceRangeWhenCreated;
AttachedPropertyWrapperScope(VarDecl *e)
: decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) {
ASTScopeAssert(sourceRangeWhenCreated.isValid(),
"VarDecls must have ranges to be looked-up");
}
virtual ~AttachedPropertyWrapperScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<const void> addressForPrinting() const override { return decl; }
virtual NullablePtr<DeclContext> getDeclContext() const override;
static SourceRange getSourceRangeOfVarDecl(const VarDecl *);
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
};
/// 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 forEachVarDeclWithLocalizableAccessors(
ScopeCreator &scopeCreator, function_ref<void(VarDecl *)> foundOne) const;
public:
bool isLastEntry() const;
NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
};
class PatternEntryDeclScope final : public AbstractPatternEntryScope {
const Expr *initWhenLastExpanded;
unsigned varCountWhenLastExpanded = 0;
public:
PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex,
DeclVisibilityKind vis)
: AbstractPatternEntryScope(pbDecl, entryIndex, vis) {}
virtual ~PatternEntryDeclScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrentIfWasExpanded() const override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<const void> getReferrent() const override;
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
};
class PatternEntryInitializerScope final : public AbstractPatternEntryScope {
// Should be able to remove this when rdar://53921703 is accomplished.
Expr *initAsWrittenWhenCreated;
public:
PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex,
DeclVisibilityKind vis)
: AbstractPatternEntryScope(pbDecl, entryIndex, vis),
initAsWrittenWhenCreated(
pbDecl->getPatternList()[entryIndex].getOriginalInit()) {}
virtual ~PatternEntryInitializerScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override;
Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const override;
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
Optional<bool>
resolveIsCascadingUseForThisScope(Optional<bool>) 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 stmt;
const unsigned index;
const SourceLoc endLoc; // cannot get it from the stmt
ConditionalClauseScope(LabeledConditionalStmt *stmt, unsigned index,
SourceLoc endLoc)
: stmt(stmt), index(index), endLoc(endLoc) {}
virtual ~ConditionalClauseScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
protected:
void printSpecifics(llvm::raw_ostream &out) const override;
public:
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
private:
ArrayRef<StmtConditionElement> getCond() const;
const StmtConditionElement &getStmtConditionElement() const;
};
/// 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 {
Pattern *const pattern;
const SourceLoc startLoc;
public:
ConditionalClausePatternUseScope(Pattern *pattern, SourceLoc startLoc)
: pattern(pattern), startLoc(startLoc) {}
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
std::string getClassName() const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
void printSpecifics(llvm::raw_ostream &out) 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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<DeclContext> getDeclContext() const override;
NullablePtr<Expr> getExprIfAny() const override { return expr; }
Expr *getExpr() const { return expr; }
NullablePtr<const void> getReferrent() 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<CaptureListExpr> captureList;
ClosureExpr *const closureExpr;
AbstractClosureScope(ClosureExpr *closureExpr,
NullablePtr<CaptureListExpr> captureList)
: captureList(captureList), closureExpr(closureExpr) {}
virtual ~AbstractClosureScope() {}
NullablePtr<ClosureExpr> getClosureIfClosureScope() const override;
NullablePtr<DeclContext> getDeclContext() const override {
return closureExpr;
}
NullablePtr<const void> addressForPrinting() const override {
return closureExpr;
}
};
class WholeClosureScope final : public AbstractClosureScope {
const BraceStmt *bodyWhenLastExpanded;
public:
WholeClosureScope(ClosureExpr *closureExpr,
NullablePtr<CaptureListExpr> captureList)
: AbstractClosureScope(closureExpr, captureList) {}
virtual ~WholeClosureScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrentIfWasExpanded() const override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<Expr> getExprIfAny() const override { return closureExpr; }
Expr *getExpr() const { return closureExpr; }
NullablePtr<const void> getReferrent() 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<CaptureListExpr> captureList)
: AbstractClosureScope(closureExpr, captureList) {}
virtual ~ClosureParametersScope() {}
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
Optional<bool> resolveIsCascadingUseForThisScope(
Optional<bool> 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<CaptureListExpr> captureList)
: AbstractClosureScope(closureExpr, captureList) {}
virtual ~ClosureBodyScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
Optional<bool> resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const override;
};
class TopLevelCodeScope final : public ASTScopeImpl {
public:
TopLevelCodeDecl *const decl;
BraceStmt *bodyWhenLastExpanded;
TopLevelCodeScope(TopLevelCodeDecl *e) : decl(e) {}
virtual ~TopLevelCodeScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrentIfWasExpanded() const override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
std::vector<ASTScopeImpl *> rescueBodyScopesToReuse();
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override {
return decl;
}
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
NullablePtr<const void> getReferrent() const override;
NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
};
/// 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
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<const void> addressForPrinting() const override {
return specializeAttr;
}
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override;
NullablePtr<DeclAttribute> getDeclAttributeIfAny() const override {
return specializeAttr;
}
NullablePtr<const void> getReferrent() const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
};
// SWIFT_ENABLE_TENSORFLOW
/// 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;
ValueDecl *const attributedDeclaration;
DifferentiableAttributeScope(DifferentiableAttr *diffAttr,
ValueDecl *decl)
: differentiableAttr(diffAttr), attributedDeclaration(decl) {
}
virtual ~DifferentiableAttributeScope() {}
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
NullablePtr<const void> addressForPrinting() const override {
return differentiableAttr;
}
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override;
NullablePtr<DeclAttribute> getDeclAttributeIfAny() const override {
return differentiableAttr;
}
NullablePtr<const void> getReferrent() const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
bool doesContextMatchStartingContext(const DeclContext *) const override;
};
// SWIFT_ENABLE_TENSORFLOW END
class SubscriptDeclScope final : public ASTScopeImpl {
public:
SubscriptDecl *const decl;
SubscriptDeclScope(SubscriptDecl *e) : decl(e) {}
virtual ~SubscriptDeclScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
void printSpecifics(llvm::raw_ostream &out) const override;
public:
virtual NullablePtr<DeclContext> getDeclContext() const override {
return decl;
}
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
NullablePtr<const void> getReferrent() const override;
protected:
SourceRange
getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override;
NullablePtr<const GenericParamList> genericParams() const override;
NullablePtr<AbstractStorageDecl>
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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
void printSpecifics(llvm::raw_ostream &out) const override;
public:
virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
NullablePtr<const void> getReferrent() const override;
NullablePtr<AbstractStorageDecl>
getEnclosingAbstractStorageDecl() const override {
return decl;
}
bool isThisAnAbstractStorageDecl() const override { return true; }
};
class EnumElementScope : public ASTScopeImpl {
EnumElementDecl *const decl;
public:
EnumElementScope(EnumElementDecl *e) : decl(e) {}
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
std::string getClassName() const override;
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
NullablePtr<DeclContext> getDeclContext() const override { return decl; }
NullablePtr<Decl> getDeclIfAny() const override { return decl; }
Decl *getDecl() const { return decl; }
protected:
SourceRange
getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
};
class AbstractStmtScope : public ASTScopeImpl {
public:
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual Stmt *getStmt() const = 0;
NullablePtr<Stmt> getStmtIfAny() const override { return getStmt(); }
NullablePtr<const void> getReferrent() 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 *createNestedConditionalClauseScopes(ScopeCreator &,
const Stmt *afterConds);
};
class IfStmtScope final : public LabeledConditionalStmtScope {
public:
IfStmt *const stmt;
IfStmtScope(IfStmt *e) : stmt(e) {}
virtual ~IfStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
LabeledConditionalStmt *getLabeledConditionalStmt() const override;
};
class WhileStmtScope final : public LabeledConditionalStmtScope {
public:
WhileStmt *const stmt;
WhileStmtScope(WhileStmt *e) : stmt(e) {}
virtual ~WhileStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
LabeledConditionalStmt *getLabeledConditionalStmt() const override;
};
class GuardStmtScope final : public LabeledConditionalStmtScope {
public:
GuardStmt *const stmt;
GuardStmtScope(GuardStmt *e) : stmt(e) {}
virtual ~GuardStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
LabeledConditionalStmt *getLabeledConditionalStmt() const override;
};
/// A scope after a guard statement that follows lookups into the conditions
/// Also for:
/// The insertion point of the last statement of an active clause in an #if
/// must be the lookup parent
/// of any following scopes. But the active clause may not be the last clause.
/// In sort, this is another case where the lookup parent cannot follow the same
/// nesting as the source order. IfConfigUseScope implements this twist. It
/// follows the IfConfig, wraps all subsequent scopes, and redirects the lookup.
class LookupParentDiversionScope final : public ASTScopeImpl {
public:
ASTScopeImpl *const lookupParent;
const SourceLoc startLoc;
LookupParentDiversionScope(ASTScopeImpl *lookupParent, SourceLoc startLoc)
: lookupParent(lookupParent), startLoc(startLoc) {}
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
std::string getClassName() const override;
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
NullablePtr<const ASTScopeImpl> getLookupParent() const override {
return lookupParent;
}
};
class RepeatWhileScope final : public AbstractStmtScope {
public:
RepeatWhileStmt *const stmt;
RepeatWhileScope(RepeatWhileStmt *e) : stmt(e) {}
virtual ~RepeatWhileScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
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() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
Stmt *getStmt() const override { return stmt; }
};
class ForEachPatternScope final : public ASTScopeImpl {
public:
ForEachStmt *const stmt;
ForEachPatternScope(ForEachStmt *e) : stmt(e) {}
virtual ~ForEachPatternScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
};
class CatchStmtScope final : public AbstractStmtScope {
public:
CatchStmt *const stmt;
CatchStmtScope(CatchStmt *e) : stmt(e) {}
virtual ~CatchStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
Stmt *getStmt() const override { return stmt; }
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer) const override;
};
class CaseStmtScope final : public AbstractStmtScope {
public:
CaseStmt *const stmt;
CaseStmtScope(CaseStmt *e) : stmt(e) {}
virtual ~CaseStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
Stmt *getStmt() const override { return stmt; }
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer) const override;
};
class BraceStmtScope final : public AbstractStmtScope {
public:
BraceStmt *const stmt;
BraceStmtScope(BraceStmt *e) : stmt(e) {}
virtual ~BraceStmtScope() {}
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
private:
AnnotatedInsertionPoint
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
public:
std::string getClassName() const override;
SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
virtual NullablePtr<DeclContext> getDeclContext() const override;
NullablePtr<ClosureExpr> parentClosureIfAny() const; // public??
Stmt *getStmt() const override { return stmt; }
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const override;
};
} // namespace ast_scope
} // namespace swift
#endif // SWIFT_AST_AST_SCOPE_H