Files
swift-mirror/lib/AST/ASTScopeCreation.cpp
Holly Borla 97ecb9435f [ASTScope] Always skip implicit attributes.
ASTScope only cares about attributes when lookup can be done inside of the
attribute, which isn't the case for implicit attributes because they're
typically built fully type-checked. This also avoids a crash when an
implicit attribute does not have a source range.
2021-04-06 16:38:46 -07:00

1222 lines
43 KiB
C++

//===--- ASTScopeCreation.cpp - Swift Object-Oriented AST Scope -----------===//
//
// 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 implements the creation methods of the ASTScopeImpl ontology.
///
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTScope.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <unordered_set>
using namespace swift;
using namespace ast_scope;
namespace swift {
namespace ast_scope {
#pragma mark ScopeCreator
class ScopeCreator final {
friend class ASTSourceFileScope;
/// For allocating scopes.
ASTContext &ctx;
public:
ASTSourceFileScope *const sourceFileScope;
ASTContext &getASTContext() const { return ctx; }
ScopeCreator(SourceFile *SF)
: ctx(SF->getASTContext()),
sourceFileScope(new (ctx) ASTSourceFileScope(SF, this)) {}
ScopeCreator(const ScopeCreator &) = delete; // ensure no copies
ScopeCreator(const ScopeCreator &&) = delete; // ensure no moves
public:
/// For each of searching, call this unless the insertion point is needed
void addToScopeTree(ASTNode n, ASTScopeImpl *parent) {
(void)addToScopeTreeAndReturnInsertionPoint(n, parent, None);
}
/// Return new insertion point.
/// For ease of searching, don't call unless insertion point is needed
///
/// \param endLoc The end location for any "scopes until the end" that
/// we introduce here, such as PatternEntryDeclScope and GuardStmtScope
ASTScopeImpl *
addToScopeTreeAndReturnInsertionPoint(ASTNode, ASTScopeImpl *parent,
Optional<SourceLoc> endLoc);
template <typename Scope, typename... Args>
ASTScopeImpl *constructExpandAndInsert(ASTScopeImpl *parent, Args... args) {
auto *child = new (ctx) Scope(args...);
parent->addChild(child, ctx);
if (auto *ip = child->insertionPointForDeferredExpansion().getPtrOrNull())
return ip;
ASTScopeImpl *insertionPoint = child->expandAndBeCurrent(*this);
return insertionPoint;
}
public:
template <typename Scope, typename PortionClass, typename... Args>
ASTScopeImpl *constructWithPortionExpandAndInsert(ASTScopeImpl *parent,
Args... args) {
const Portion *portion = new (ctx) PortionClass();
return constructExpandAndInsert<Scope>(parent, portion, args...);
}
void addExprToScopeTree(Expr *expr, ASTScopeImpl *parent) {
// Use the ASTWalker to find buried captures and closures
ASTScopeAssert(expr,
"If looking for closures, must have an expression to search.");
/// AST walker that finds top-level closures in an expression.
class ClosureFinder : public ASTWalker {
ScopeCreator &scopeCreator;
ASTScopeImpl *parent;
public:
ClosureFinder(ScopeCreator &scopeCreator, ASTScopeImpl *parent)
: scopeCreator(scopeCreator), parent(parent) {}
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
scopeCreator
.constructExpandAndInsert<ClosureParametersScope>(
parent, closure);
return {false, E};
}
if (auto *capture = dyn_cast<CaptureListExpr>(E)) {
scopeCreator
.constructExpandAndInsert<CaptureListScope>(
parent, capture);
return {false, E};
}
return {true, E};
}
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
if (isa<BraceStmt>(S)) { // closures hidden in here
return {true, S};
}
return {false, S};
}
std::pair<bool, Pattern *> walkToPatternPre(Pattern *P) override {
return {false, P};
}
bool walkToDeclPre(Decl *D) override { return false; }
bool walkToTypeReprPre(TypeRepr *T) override { return false; }
bool walkToParameterListPre(ParameterList *PL) override { return false; }
};
expr->walk(ClosureFinder(*this, parent));
}
public:
/// Create the matryoshka nested generic param scopes (if any)
/// that are subscopes of the receiver. Return
/// the furthest descendant.
/// Last GenericParamsScope includes the where clause
ASTScopeImpl *addNestedGenericParamScopesToTree(Decl *parameterizedDecl,
GenericParamList *generics,
ASTScopeImpl *parent) {
if (!generics)
return parent;
auto *s = parent;
for (unsigned i : indices(generics->getParams()))
s = constructExpandAndInsert<GenericParamScope>(
s, parameterizedDecl, generics, i);
return s;
}
void
addChildrenForParsedAccessors(AbstractStorageDecl *asd,
ASTScopeImpl *parent);
void addChildrenForKnownAttributes(ValueDecl *decl,
ASTScopeImpl *parent);
/// Add PatternEntryDeclScopes for each pattern binding entry.
///
/// Returns the new insertion point.
///
/// \param endLoc Must be valid iff the pattern binding is in a local
/// scope, in which case this is the last source location where the
/// pattern bindings are going to be visible.
ASTScopeImpl *
addPatternBindingToScopeTree(PatternBindingDecl *patternBinding,
ASTScopeImpl *parent,
Optional<SourceLoc> endLoc);
SWIFT_DEBUG_DUMP { print(llvm::errs()); }
void print(raw_ostream &out) const {
out << "(swift::ASTSourceFileScope*) " << sourceFileScope << "\n";
}
// Make vanilla new illegal.
void *operator new(size_t bytes) = delete;
// 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(ScopeCreator));
void *operator new(size_t Bytes, void *Mem) {
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
};
} // ast_scope
} // namespace swift
#pragma mark Scope tree creation and extension
ASTScope::ASTScope(SourceFile *SF) : impl(createScopeTree(SF)) {}
void ASTScope::buildFullyExpandedTree() { impl->buildFullyExpandedTree(); }
void ASTScope::
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() {
impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
}
void ASTScope::expandFunctionBody(AbstractFunctionDecl *AFD) {
// There is no source file associated with C++ decl contexts, so there will
// be no parent source file if AFD is a C++ function.
if (auto *const SF = AFD->getParentSourceFile())
SF->getScope().expandFunctionBodyImpl(AFD);
}
void ASTScope::expandFunctionBodyImpl(AbstractFunctionDecl *AFD) {
impl->expandFunctionBody(AFD);
}
ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) {
ScopeCreator *scopeCreator = new (SF->getASTContext()) ScopeCreator(SF);
return scopeCreator->sourceFileScope;
}
void ASTSourceFileScope::buildFullyExpandedTree() {
if (!getWasExpanded())
expandAndBeCurrent(*scopeCreator);
preOrderChildrenDo([&](ASTScopeImpl *s) {
if (!s->getWasExpanded())
s->expandAndBeCurrent(*scopeCreator);
});
}
void ASTSourceFileScope::
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() {
if (!getWasExpanded())
expandAndBeCurrent(*scopeCreator);
}
void ASTSourceFileScope::expandFunctionBody(AbstractFunctionDecl *AFD) {
if (!AFD)
return;
auto sr = AFD->getOriginalBodySourceRange();
if (sr.isInvalid())
return;
ASTScopeImpl *bodyScope = findInnermostEnclosingScope(sr.Start, nullptr);
if (!bodyScope->getWasExpanded())
bodyScope->expandAndBeCurrent(*scopeCreator);
}
ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
ScopeCreator *scopeCreator)
: SF(SF), scopeCreator(scopeCreator) {}
#pragma mark NodeAdder
namespace swift {
namespace ast_scope {
class NodeAdder
: public ASTVisitor<NodeAdder, ASTScopeImpl *,
ASTScopeImpl *, ASTScopeImpl *,
void, void, void, ASTScopeImpl *, ScopeCreator &> {
Optional<SourceLoc> endLoc;
public:
explicit NodeAdder(Optional<SourceLoc> endLoc) : endLoc(endLoc) {}
#pragma mark ASTNodes that do not create scopes
#define VISIT_AND_IGNORE(What) \
ASTScopeImpl *visit##What(What *w, ASTScopeImpl *p, \
ScopeCreator &) { \
return p; \
}
VISIT_AND_IGNORE(ImportDecl)
VISIT_AND_IGNORE(EnumCaseDecl)
VISIT_AND_IGNORE(PrecedenceGroupDecl)
VISIT_AND_IGNORE(InfixOperatorDecl)
VISIT_AND_IGNORE(PrefixOperatorDecl)
VISIT_AND_IGNORE(PostfixOperatorDecl)
VISIT_AND_IGNORE(GenericTypeParamDecl)
VISIT_AND_IGNORE(AssociatedTypeDecl)
VISIT_AND_IGNORE(ModuleDecl)
VISIT_AND_IGNORE(ParamDecl)
VISIT_AND_IGNORE(PoundDiagnosticDecl)
VISIT_AND_IGNORE(MissingMemberDecl)
// Only members of the active clause are in scope, and those
// are visited separately.
VISIT_AND_IGNORE(IfConfigDecl)
// This declaration is handled from the PatternBindingDecl
VISIT_AND_IGNORE(VarDecl)
// These contain nothing to scope.
VISIT_AND_IGNORE(BreakStmt)
VISIT_AND_IGNORE(ContinueStmt)
VISIT_AND_IGNORE(FallthroughStmt)
VISIT_AND_IGNORE(FailStmt)
#undef VISIT_AND_IGNORE
#pragma mark simple creation ignoring deferred nodes
#define VISIT_AND_CREATE(What, ScopeClass) \
ASTScopeImpl *visit##What(What *w, ASTScopeImpl *p, \
ScopeCreator &scopeCreator) { \
return scopeCreator.constructExpandAndInsert<ScopeClass>(p, w); \
}
VISIT_AND_CREATE(SubscriptDecl, SubscriptDeclScope)
VISIT_AND_CREATE(IfStmt, IfStmtScope)
VISIT_AND_CREATE(WhileStmt, WhileStmtScope)
VISIT_AND_CREATE(RepeatWhileStmt, RepeatWhileScope)
VISIT_AND_CREATE(DoStmt, DoStmtScope)
VISIT_AND_CREATE(DoCatchStmt, DoCatchStmtScope)
VISIT_AND_CREATE(SwitchStmt, SwitchStmtScope)
VISIT_AND_CREATE(ForEachStmt, ForEachStmtScope)
VISIT_AND_CREATE(CaseStmt, CaseStmtScope)
VISIT_AND_CREATE(AbstractFunctionDecl, AbstractFunctionDeclScope)
#undef VISIT_AND_CREATE
#pragma mark 2D simple creation (ignoring deferred nodes)
#define VISIT_AND_CREATE_WHOLE_PORTION(What, WhatScope) \
ASTScopeImpl *visit##What(What *w, ASTScopeImpl *p, \
ScopeCreator &scopeCreator) { \
return scopeCreator.constructWithPortionExpandAndInsert< \
WhatScope, GenericTypeOrExtensionWholePortion>(p, w); \
}
VISIT_AND_CREATE_WHOLE_PORTION(ExtensionDecl, ExtensionScope)
VISIT_AND_CREATE_WHOLE_PORTION(StructDecl, NominalTypeScope)
VISIT_AND_CREATE_WHOLE_PORTION(ClassDecl, NominalTypeScope)
VISIT_AND_CREATE_WHOLE_PORTION(ProtocolDecl, NominalTypeScope)
VISIT_AND_CREATE_WHOLE_PORTION(EnumDecl, NominalTypeScope)
VISIT_AND_CREATE_WHOLE_PORTION(TypeAliasDecl, TypeAliasScope)
VISIT_AND_CREATE_WHOLE_PORTION(OpaqueTypeDecl, OpaqueTypeScope)
#undef VISIT_AND_CREATE_WHOLE_PORTION
// This declaration is handled from
// addChildrenForParsedAccessors
ASTScopeImpl *visitAccessorDecl(AccessorDecl *ad, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
return visitAbstractFunctionDecl(ad, p, scopeCreator);
}
#pragma mark simple creation with deferred nodes
// Each of the following creates a new scope, so that nodes which were parsed
// after them need to be placed in scopes BELOW them in the tree. So pass down
// the deferred nodes.
ASTScopeImpl *visitGuardStmt(GuardStmt *e, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
ASTScopeAssert(endLoc.hasValue(), "GuardStmt outside of a BraceStmt?");
return scopeCreator.constructExpandAndInsert<GuardStmtScope>(
p, e, *endLoc);
}
ASTScopeImpl *visitTopLevelCodeDecl(TopLevelCodeDecl *d,
ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
ASTScopeAssert(endLoc.hasValue(), "TopLevelCodeDecl in wrong place?");
return scopeCreator.constructExpandAndInsert<TopLevelCodeScope>(
p, d, *endLoc);
}
#pragma mark special-case creation
ASTScopeImpl *visitSourceFile(SourceFile *, ASTScopeImpl *, ScopeCreator &) {
ASTScope_unreachable("SourceFiles are orphans.");
}
ASTScopeImpl *visitYieldStmt(YieldStmt *ys, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
for (Expr *e : ys->getYields())
visitExpr(e, p, scopeCreator);
return p;
}
ASTScopeImpl *visitDeferStmt(DeferStmt *ds, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
visitFuncDecl(ds->getTempDecl(), p, scopeCreator);
return p;
}
ASTScopeImpl *visitBraceStmt(BraceStmt *bs, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
if (bs->empty())
return p;
SmallVector<ValueDecl *, 2> localFuncsAndTypes;
SmallVector<VarDecl *, 2> localVars;
// All types and functions are visible anywhere within a brace statement
// scope. When ordering matters (i.e. var decl) we will have split the brace
// statement into nested scopes.
for (auto braceElement : bs->getElements()) {
if (auto localBinding = braceElement.dyn_cast<Decl *>()) {
if (auto *vd = dyn_cast<ValueDecl>(localBinding)) {
if (isa<FuncDecl>(vd) || isa<TypeDecl>(vd)) {
localFuncsAndTypes.push_back(vd);
} else if (auto *var = dyn_cast<VarDecl>(localBinding)) {
localVars.push_back(var);
}
}
}
}
SourceLoc endLocForBraceStmt = bs->getEndLoc();
if (endLoc.hasValue())
endLocForBraceStmt = *endLoc;
ASTContext &ctx = scopeCreator.getASTContext();
return
scopeCreator.constructExpandAndInsert<BraceStmtScope>(
p, bs,
ctx.AllocateCopy(localFuncsAndTypes),
ctx.AllocateCopy(localVars),
endLocForBraceStmt);
}
ASTScopeImpl *
visitPatternBindingDecl(PatternBindingDecl *patternBinding,
ASTScopeImpl *parentScope,
ScopeCreator &scopeCreator) {
return scopeCreator.addPatternBindingToScopeTree(
patternBinding, parentScope, endLoc);
}
ASTScopeImpl *visitEnumElementDecl(EnumElementDecl *eed,
ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
scopeCreator.constructExpandAndInsert<EnumElementScope>(p, eed);
return p;
}
ASTScopeImpl *visitReturnStmt(ReturnStmt *rs, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
if (rs->hasResult())
visitExpr(rs->getResult(), p, scopeCreator);
return p;
}
ASTScopeImpl *visitThrowStmt(ThrowStmt *ts, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
visitExpr(ts->getSubExpr(), p, scopeCreator);
return p;
}
ASTScopeImpl *visitPoundAssertStmt(PoundAssertStmt *pas,
ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
visitExpr(pas->getCondition(), p, scopeCreator);
return p;
}
ASTScopeImpl *visitExpr(Expr *expr, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
if (expr)
scopeCreator.addExprToScopeTree(expr, p);
return p;
}
};
} // namespace ast_scope
} // namespace swift
// These definitions are way down here so it can call into
// NodeAdder
ASTScopeImpl *
ScopeCreator::addToScopeTreeAndReturnInsertionPoint(ASTNode n,
ASTScopeImpl *parent,
Optional<SourceLoc> endLoc) {
if (!n)
return parent;
if (auto *d = n.dyn_cast<Decl *>())
if (d->isImplicit())
return parent;
NodeAdder adder(endLoc);
if (auto *p = n.dyn_cast<Decl *>())
return adder.visit(p, parent, *this);
if (auto *p = n.dyn_cast<Expr *>())
return adder.visit(p, parent, *this);
auto *p = n.get<Stmt *>();
return adder.visit(p, parent, *this);
}
void ScopeCreator::addChildrenForParsedAccessors(
AbstractStorageDecl *asd, ASTScopeImpl *parent) {
asd->visitParsedAccessors([&](AccessorDecl *ad) {
assert(asd == ad->getStorage());
this->addToScopeTree(ad, parent);
});
}
void ScopeCreator::addChildrenForKnownAttributes(ValueDecl *decl,
ASTScopeImpl *parent) {
SmallVector<DeclAttribute *, 2> relevantAttrs;
for (auto *attr : decl->getAttrs()) {
if (attr->isImplicit())
continue;
if (isa<DifferentiableAttr>(attr))
relevantAttrs.push_back(attr);
if (isa<SpecializeAttr>(attr))
relevantAttrs.push_back(attr);
if (isa<CustomAttr>(attr))
relevantAttrs.push_back(attr);
}
// Decl::getAttrs() is a linked list with head insertion, so the
// attributes are in reverse source order.
std::reverse(relevantAttrs.begin(), relevantAttrs.end());
for (auto *attr : relevantAttrs) {
if (auto *diffAttr = dyn_cast<DifferentiableAttr>(attr)) {
constructExpandAndInsert<DifferentiableAttributeScope>(
parent, diffAttr, decl);
} else if (auto *specAttr = dyn_cast<SpecializeAttr>(attr)) {
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
constructExpandAndInsert<SpecializeAttributeScope>(
parent, specAttr, afd);
}
} else if (auto *customAttr = dyn_cast<CustomAttr>(attr)) {
if (auto *vd = dyn_cast<VarDecl>(decl)) {
constructExpandAndInsert<AttachedPropertyWrapperScope>(
parent, customAttr, vd);
}
}
}
}
ASTScopeImpl *
ScopeCreator::addPatternBindingToScopeTree(PatternBindingDecl *patternBinding,
ASTScopeImpl *parentScope,
Optional<SourceLoc> endLoc) {
if (auto *var = patternBinding->getSingleVar())
addChildrenForKnownAttributes(var, parentScope);
bool isLocalBinding = false;
for (auto i : range(patternBinding->getNumPatternEntries())) {
if (auto *varDecl = patternBinding->getAnchoringVarDecl(i)) {
isLocalBinding = varDecl->getDeclContext()->isLocalContext();
break;
}
}
auto *insertionPoint = parentScope;
for (auto i : range(patternBinding->getNumPatternEntries())) {
Optional<SourceLoc> endLocForBinding = None;
if (isLocalBinding) {
endLocForBinding = endLoc;
ASTScopeAssert(endLoc.hasValue() && endLoc->isValid(),
"PatternBindingDecl in local context outside of BraceStmt?");
}
insertionPoint =
constructExpandAndInsert<PatternEntryDeclScope>(
insertionPoint, patternBinding, i,
isLocalBinding, endLocForBinding);
ASTScopeAssert(isLocalBinding || insertionPoint == parentScope,
"Bindings at the top-level or members of types should "
"not change the insertion point");
}
return insertionPoint;
}
#pragma mark creation helpers
void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) {
ASTScopeAssert(!child->getParent(), "child should not already have parent");
child->parentAndWasExpanded.setPointer(this);
#ifndef NDEBUG
checkSourceRangeBeforeAddingChild(child, ctx);
#endif
// If this is the first time we've added children, notify the ASTContext
// that there's a SmallVector that needs to be cleaned up.
if (storedChildren.empty())
ctx.addDestructorCleanup(storedChildren);
storedChildren.push_back(child);
}
#pragma mark implementations of expansion
ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
ASTScopeAssert(!getWasExpanded(),
"Cannot expand the same scope twice");
// Set the flag before we actually expand, to detect re-entrant calls
// via the above assertion.
setWasExpanded();
if (auto *s = scopeCreator.getASTContext().Stats)
++s->getFrontendCounters().NumASTScopeExpansions;
auto *insertionPoint = expandSpecifically(scopeCreator);
ASTScopeAssert(!insertionPointForDeferredExpansion() ||
insertionPointForDeferredExpansion().get() ==
insertionPoint,
"In order for lookups into lazily-expanded scopes to be "
"accurate before expansion, the insertion point before "
"expansion must be the same as after expansion.");
return insertionPoint;
}
// Do this whole bit so it's easy to see which type of scope is which
#define CREATES_NEW_INSERTION_POINT(Scope) \
ASTScopeImpl *Scope::expandSpecifically(ScopeCreator &scopeCreator) { \
return expandAScopeThatCreatesANewInsertionPoint(scopeCreator) \
.insertionPoint; \
}
#define NO_NEW_INSERTION_POINT(Scope) \
ASTScopeImpl *Scope::expandSpecifically(ScopeCreator &scopeCreator) { \
expandAScopeThatDoesNotCreateANewInsertionPoint(scopeCreator); \
return getParent().get(); \
}
// Return this in particular for GenericParamScope so body is scoped under it
#define NO_EXPANSION(Scope) \
ASTScopeImpl *Scope::expandSpecifically(ScopeCreator &) { return this; }
CREATES_NEW_INSERTION_POINT(ASTSourceFileScope)
CREATES_NEW_INSERTION_POINT(GuardStmtScope)
CREATES_NEW_INSERTION_POINT(PatternEntryDeclScope)
CREATES_NEW_INSERTION_POINT(GenericTypeOrExtensionScope)
CREATES_NEW_INSERTION_POINT(BraceStmtScope)
CREATES_NEW_INSERTION_POINT(TopLevelCodeScope)
CREATES_NEW_INSERTION_POINT(ConditionalClausePatternUseScope)
NO_NEW_INSERTION_POINT(FunctionBodyScope)
NO_NEW_INSERTION_POINT(AbstractFunctionDeclScope)
NO_NEW_INSERTION_POINT(AttachedPropertyWrapperScope)
NO_NEW_INSERTION_POINT(EnumElementScope)
NO_NEW_INSERTION_POINT(GuardStmtBodyScope)
NO_NEW_INSERTION_POINT(ParameterListScope)
NO_NEW_INSERTION_POINT(PatternEntryInitializerScope)
NO_NEW_INSERTION_POINT(CaptureListScope)
NO_NEW_INSERTION_POINT(CaseStmtScope)
NO_NEW_INSERTION_POINT(CaseLabelItemScope)
NO_NEW_INSERTION_POINT(CaseStmtBodyScope)
NO_NEW_INSERTION_POINT(ConditionalClauseInitializerScope)
NO_NEW_INSERTION_POINT(ClosureParametersScope)
NO_NEW_INSERTION_POINT(DefaultArgumentInitializerScope)
NO_NEW_INSERTION_POINT(DoStmtScope)
NO_NEW_INSERTION_POINT(DoCatchStmtScope)
NO_NEW_INSERTION_POINT(ForEachPatternScope)
NO_NEW_INSERTION_POINT(ForEachStmtScope)
NO_NEW_INSERTION_POINT(IfStmtScope)
NO_NEW_INSERTION_POINT(RepeatWhileScope)
NO_NEW_INSERTION_POINT(SubscriptDeclScope)
NO_NEW_INSERTION_POINT(SwitchStmtScope)
NO_NEW_INSERTION_POINT(WhileStmtScope)
NO_EXPANSION(GenericParamScope)
NO_EXPANSION(SpecializeAttributeScope)
NO_EXPANSION(DifferentiableAttributeScope)
#undef CREATES_NEW_INSERTION_POINT
#undef NO_NEW_INSERTION_POINT
AnnotatedInsertionPoint
ASTSourceFileScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator &scopeCreator) {
ASTScopeAssert(SF, "Must already have a SourceFile.");
SourceLoc endLoc = getSourceRangeOfThisASTNode().End;
ASTScopeImpl *insertionPoint = this;
for (auto *d : SF->getTopLevelDecls()) {
insertionPoint = scopeCreator.addToScopeTreeAndReturnInsertionPoint(
ASTNode(d), insertionPoint, endLoc);
}
return {insertionPoint, "Next time decls are added they go here."};
}
void
ParameterListScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
// Each initializer for a function parameter is its own, sibling, scope.
// Unlike generic parameters or pattern initializers, it cannot refer to a
// previous parameter.
for (ParamDecl *pd : params->getArray()) {
if (pd->hasDefaultExpr())
scopeCreator
.constructExpandAndInsert<DefaultArgumentInitializerScope>(
this, pd);
}
}
AnnotatedInsertionPoint
PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator &scopeCreator) {
// Initializers come before VarDecls, e.g. PCMacro/didSet.swift 19
auto patternEntry = getPatternEntry();
// Create a child for the initializer, if present.
// Cannot trust the source range given in the ASTScopeImpl for the end of the
// initializer (because of InterpolatedLiteralStrings and EditorPlaceHolders),
// so compute it ourselves.
// Even if this predicate fails, there may be an initContext but
// we cannot make a scope for it, since no source range.
if (patternEntry.getOriginalInit()) {
ASTScopeAssert(
patternEntry.getOriginalInit()->getSourceRange().isValid(),
"pattern initializer has invalid source range");
ASTScopeAssert(
!getSourceManager().isBeforeInBuffer(
patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()),
"Original inits are always after the '='");
scopeCreator
.constructExpandAndInsert<PatternEntryInitializerScope>(
this, decl, patternEntryIndex);
}
// Add accessors for the variables in this pattern.
patternEntry.getPattern()->forEachVariable([&](VarDecl *var) {
scopeCreator.addChildrenForParsedAccessors(var, this);
});
// In local context, the PatternEntryDeclScope becomes the insertion point, so
// that all any bindings introduecd by the pattern are in scope for subsequent
// lookups.
if (isLocalBinding)
return {this, "All code that follows is inside this scope"};
return {getParent().get(), "Global and type members do not introduce scopes"};
}
void
PatternEntryInitializerScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
// Create a child for the initializer expression.
scopeCreator.addToScopeTree(ASTNode(getPatternEntry().getOriginalInit()),
this);
}
AnnotatedInsertionPoint
ConditionalClausePatternUseScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator &scopeCreator) {
auto *initializer = sec.getInitializer();
if (!isa<ErrorExpr>(initializer)) {
scopeCreator
.constructExpandAndInsert<ConditionalClauseInitializerScope>(
this, initializer);
}
return {this,
"Succeeding code must be in scope of conditional clause pattern bindings"};
}
void
ConditionalClauseInitializerScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(ASTNode(initializer), this);
}
void
GuardStmtBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &
scopeCreator) {
scopeCreator.addToScopeTree(ASTNode(body), this);
}
AnnotatedInsertionPoint
GuardStmtScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
scopeCreator) {
ASTScopeImpl *conditionLookupParent =
createNestedConditionalClauseScopes(scopeCreator, endLoc);
// Add a child for the 'guard' body, which always exits.
// The lookup parent is whole guard stmt scope, NOT the cond scopes
auto *body = stmt->getBody();
if (!body->empty()) {
scopeCreator
.constructExpandAndInsert<GuardStmtBodyScope>(
conditionLookupParent, this, stmt->getBody());
}
return {conditionLookupParent,
"Succeeding code must be in scope of guard variables"};
}
AnnotatedInsertionPoint
GenericTypeOrExtensionScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator & scopeCreator) {
return {portion->expandScope(this, scopeCreator),
"<X: Foo, Y: X> is legal, so nest these"};
}
AnnotatedInsertionPoint
BraceStmtScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator &scopeCreator) {
ASTScopeImpl *insertionPoint = this;
for (auto nd : stmt->getElements()) {
insertionPoint = scopeCreator.addToScopeTreeAndReturnInsertionPoint(
nd, insertionPoint, endLoc);
}
return {
insertionPoint,
"For top-level code decls, need the scope under, say a guard statment."};
}
AnnotatedInsertionPoint
TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
scopeCreator) {
auto *body =
scopeCreator
.addToScopeTreeAndReturnInsertionPoint(decl->getBody(), this, endLoc);
return {body, "So next top level code scope and put its decls in its body "
"under a guard statement scope (etc) from the last top level "
"code scope"};
}
#pragma mark expandAScopeThatDoesNotCreateANewInsertionPoint
// Create child scopes for every declaration in a body.
void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addChildrenForKnownAttributes(decl, this);
// Create scopes for generic and ordinary parameters.
// For a subscript declaration, the generic and ordinary parameters are in an
// ancestor scope, so don't make them here.
ASTScopeImpl *leaf = this;
if (!isa<AccessorDecl>(decl)) {
leaf = scopeCreator.addNestedGenericParamScopesToTree(
decl, decl->getGenericParams(), leaf);
auto *params = decl->getParameters();
if (params->size() > 0) {
scopeCreator.constructExpandAndInsert<ParameterListScope>(
leaf, params, nullptr);
}
}
// Create scope for the body.
// We create body scopes when there is no body for source kit to complete
// erroneous code in bodies.
if (decl->getBodySourceRange().isValid()) {
scopeCreator.constructExpandAndInsert<FunctionBodyScope>(leaf, decl);
}
}
void EnumElementScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
if (auto *pl = decl->getParameterList())
scopeCreator.constructExpandAndInsert<ParameterListScope>(this, pl, nullptr);
// The invariant that the raw value expression can never introduce a new scope
// is checked in Parse. However, this guarantee is not future-proof. Compute
// and add the raw value expression anyways just to be defensive.
//
// FIXME: Re-enable this. It currently crashes for malformed enum cases.
// scopeCreator.addToScopeTree(decl->getStructuralRawValueExpr(), this);
}
void FunctionBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
expandBody(scopeCreator);
}
void IfStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
auto *thenStmt = stmt->getThenStmt();
auto *elseStmt = stmt->getElseStmt();
SourceLoc endLoc = thenStmt->getEndLoc();
ASTScopeImpl *insertionPoint =
createNestedConditionalClauseScopes(scopeCreator, endLoc);
// The 'then' branch
scopeCreator.addToScopeTree(thenStmt, insertionPoint);
// Result builders can add an 'else' block consisting entirely of
// implicit expressions. In this case, the end location of the
// 'then' block is equal to the start location of the 'else'
// block, and the 'else' block source range is empty.
if (elseStmt &&
thenStmt->getEndLoc() == elseStmt->getStartLoc() &&
elseStmt->getStartLoc() == elseStmt->getEndLoc())
return;
// Add the 'else' branch, if needed.
scopeCreator.addToScopeTree(elseStmt, this);
}
void WhileStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
SourceLoc endLoc = stmt->getBody()->getEndLoc();
ASTScopeImpl *insertionPoint =
createNestedConditionalClauseScopes(scopeCreator, endLoc);
scopeCreator.addToScopeTree(stmt->getBody(), insertionPoint);
}
void RepeatWhileScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getBody(), this);
scopeCreator.addToScopeTree(stmt->getCond(), this);
}
void DoStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getBody(), this);
}
void DoCatchStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getBody(), this);
for (auto catchClause : stmt->getCatches())
scopeCreator.addToScopeTree(catchClause, this);
}
void SwitchStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getSubjectExpr(), this);
for (auto caseStmt : stmt->getCases()) {
ASTScopeAssert(
caseStmt->getSourceRange().isValid(),
"pattern initializer has invalid source range");
scopeCreator.constructExpandAndInsert<CaseStmtScope>(this, caseStmt);
}
}
void ForEachStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getSequence(), this);
// Add a child describing the scope of the pattern.
// In error cases such as:
// let v: C { for b : Int -> S((array: P { }
// the body is implicit and it would overlap the source range of the expr
// above.
if (!stmt->getBody()->isImplicit()) {
ASTScopeAssert(
stmt->getBody()->getSourceRange().isValid(),
"pattern initializer has invalid source range");
scopeCreator.constructExpandAndInsert<ForEachPatternScope>(this, stmt);
}
}
void ForEachPatternScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getWhere(), this);
scopeCreator.addToScopeTree(stmt->getBody(), this);
}
void CaseStmtScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
for (auto &item : stmt->getCaseLabelItems()) {
if (item.getGuardExpr()) {
scopeCreator.constructExpandAndInsert<CaseLabelItemScope>(this, item);
}
}
if (!stmt->getBody()->empty()) {
scopeCreator.constructExpandAndInsert<CaseStmtBodyScope>(this, stmt);
}
}
void CaseLabelItemScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(item.getGuardExpr(), this);
}
void CaseStmtBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(stmt->getBody(), this);
}
void SubscriptDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addChildrenForKnownAttributes(decl, this);
auto *leaf = scopeCreator.addNestedGenericParamScopesToTree(
decl, decl->getGenericParams(), this);
scopeCreator.constructExpandAndInsert<ParameterListScope>(
leaf, decl->getIndices(), decl->getAccessor(AccessorKind::Get));
scopeCreator.addChildrenForParsedAccessors(decl, leaf);
}
void CaptureListScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
auto *closureExpr = expr->getClosureBody();
scopeCreator
.constructExpandAndInsert<ClosureParametersScope>(this, closureExpr);
}
void ClosureParametersScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(closureExpr->getBody(), this);
}
void DefaultArgumentInitializerScope::
expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
auto *initExpr = decl->getStructuralDefaultExpr();
ASTScopeAssert(initExpr,
"Default argument initializer must have an initializer.");
scopeCreator.addToScopeTree(initExpr, this);
}
void AttachedPropertyWrapperScope::
expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
if (auto *expr = attr->getArg())
scopeCreator.addToScopeTree(expr, this);
}
#pragma mark expandScope
ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope(
GenericTypeOrExtensionScope *scope, ScopeCreator &scopeCreator) const {
// Get now in case recursion emancipates scope
auto *const ip = scope->getParent().get();
auto *context = scope->getGenericContext();
auto *genericParams = (isa<TypeAliasDecl>(context)
? context->getParsedGenericParams()
: context->getGenericParams());
auto *deepestScope = scopeCreator.addNestedGenericParamScopesToTree(
scope->getDecl(), genericParams, scope);
if (context->getTrailingWhereClause())
scope->createTrailingWhereClauseScope(deepestScope, scopeCreator);
// Prevent circular request bugs caused by illegal input and
// doing lookups that getExtendedNominal in the midst of getExtendedNominal.
if (scope->shouldHaveABody() && !scope->doesDeclHaveABody())
return ip;
scope->createBodyScope(deepestScope, scopeCreator);
return ip;
}
ASTScopeImpl *
IterableTypeBodyPortion::expandScope(GenericTypeOrExtensionScope *scope,
ScopeCreator &scopeCreator) const {
// Get it now in case of recursion and this one gets emancipated
auto *const ip = scope->getParent().get();
scope->expandBody(scopeCreator);
return ip;
}
ASTScopeImpl *GenericTypeOrExtensionWherePortion::expandScope(
GenericTypeOrExtensionScope *scope, ScopeCreator &) const {
return scope->getParent().get();
}
#pragma mark createBodyScope
void ExtensionScope::createBodyScope(ASTScopeImpl *leaf,
ScopeCreator &scopeCreator) {
scopeCreator.constructWithPortionExpandAndInsert<ExtensionScope,
IterableTypeBodyPortion>(
leaf, decl);
}
void NominalTypeScope::createBodyScope(ASTScopeImpl *leaf,
ScopeCreator &scopeCreator) {
scopeCreator.constructWithPortionExpandAndInsert<NominalTypeScope,
IterableTypeBodyPortion>(
leaf, decl);
}
#pragma mark createTrailingWhereClauseScope
ASTScopeImpl *GenericTypeOrExtensionScope::createTrailingWhereClauseScope(
ASTScopeImpl *parent, ScopeCreator &scopeCreator) {
return parent;
}
ASTScopeImpl *
ExtensionScope::createTrailingWhereClauseScope(ASTScopeImpl *parent,
ScopeCreator &scopeCreator) {
return scopeCreator.constructWithPortionExpandAndInsert<
ExtensionScope, GenericTypeOrExtensionWherePortion>(parent, decl);
}
ASTScopeImpl *
NominalTypeScope::createTrailingWhereClauseScope(ASTScopeImpl *parent,
ScopeCreator &scopeCreator) {
return scopeCreator.constructWithPortionExpandAndInsert<
NominalTypeScope, GenericTypeOrExtensionWherePortion>(parent, decl);
}
ASTScopeImpl *
TypeAliasScope::createTrailingWhereClauseScope(ASTScopeImpl *parent,
ScopeCreator &scopeCreator) {
return scopeCreator.constructWithPortionExpandAndInsert<
TypeAliasScope, GenericTypeOrExtensionWherePortion>(parent, decl);
}
#pragma mark misc
ASTScopeImpl *LabeledConditionalStmtScope::createNestedConditionalClauseScopes(
ScopeCreator &scopeCreator, SourceLoc endLoc) {
auto *stmt = getLabeledConditionalStmt();
ASTScopeImpl *insertionPoint = this;
for (auto &sec : stmt->getCond()) {
switch (sec.getKind()) {
case StmtConditionElement::CK_Availability:
break;
case StmtConditionElement::CK_Boolean:
scopeCreator.addToScopeTree(sec.getBoolean(), insertionPoint);
break;
case StmtConditionElement::CK_PatternBinding:
insertionPoint =
scopeCreator.constructExpandAndInsert<
ConditionalClausePatternUseScope>(
insertionPoint, sec, endLoc);
break;
}
}
return insertionPoint;
}
AbstractPatternEntryScope::AbstractPatternEntryScope(
PatternBindingDecl *declBeingScoped, unsigned entryIndex)
: decl(declBeingScoped), patternEntryIndex(entryIndex) {
ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(),
"out of bounds");
}
#pragma mark new operators
void *ASTScopeImpl::operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment) {
return ctx.Allocate(bytes, alignment);
}
void *Portion::operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment) {
return ctx.Allocate(bytes, alignment);
}
void *ASTScope::operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment) {
return ctx.Allocate(bytes, alignment);
}
void *ScopeCreator::operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment) {
return ctx.Allocate(bytes, alignment);
}
#pragma mark - expandBody
void FunctionBodyScope::expandBody(ScopeCreator &scopeCreator) {
scopeCreator.addToScopeTree(decl->getBody(), this);
}
void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {}
void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
for (auto *d : getIterableDeclContext().get()->getMembers())
scopeCreator.addToScopeTree(ASTNode(d), this);
}
#pragma mark getScopeCreator
ScopeCreator &ASTScopeImpl::getScopeCreator() {
return getParent().get()->getScopeCreator();
}
ScopeCreator &ASTSourceFileScope::getScopeCreator() { return *scopeCreator; }
#pragma mark currency
NullablePtr<ASTScopeImpl> ASTScopeImpl::insertionPointForDeferredExpansion() {
return nullptr;
}
NullablePtr<ASTScopeImpl>
FunctionBodyScope::insertionPointForDeferredExpansion() {
return getParent().get();
}
NullablePtr<ASTScopeImpl>
IterableTypeScope::insertionPointForDeferredExpansion() {
return portion->insertionPointForDeferredExpansion(this);
}
NullablePtr<ASTScopeImpl>
GenericTypeOrExtensionWholePortion::insertionPointForDeferredExpansion(
IterableTypeScope *s) const {
return s->getParent().get();
}
NullablePtr<ASTScopeImpl>
GenericTypeOrExtensionWherePortion::insertionPointForDeferredExpansion(
IterableTypeScope *) const {
return nullptr;
}
NullablePtr<ASTScopeImpl>
IterableTypeBodyPortion::insertionPointForDeferredExpansion(
IterableTypeScope *s) const {
return s->getParent().get();
}
#pragma mark verification
void ast_scope::simple_display(llvm::raw_ostream &out,
const ScopeCreator *scopeCreator) {
scopeCreator->print(out);
}