Merge remote-tracking branch 'origin/master' into master-next

This commit is contained in:
swift-ci
2019-09-22 19:30:00 -07:00
13 changed files with 488 additions and 262 deletions

View File

@@ -38,6 +38,16 @@
#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
@@ -125,10 +135,10 @@ private:
/// Must clear source range change whenever this changes
Children storedChildren;
/// Because expansion returns an insertion point,
/// if a scope is reexpanded, the children added NOT by expansion must be
/// rescued and reused.
unsigned childrenCountWhenLastExpanded = 0;
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;
@@ -162,7 +172,7 @@ public:
void *operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment = alignof(ASTScopeImpl));
void *operator new(size_t Bytes, void *Mem) {
assert(Mem);
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
@@ -180,12 +190,13 @@ protected:
public: // for addReusedBodyScopes
void addChild(ASTScopeImpl *child, ASTContext &);
std::vector<ASTScopeImpl *> rescueYoungestChildren(unsigned count);
std::vector<ASTScopeImpl *> rescueASTAncestorScopesForReuseFromMe();
/// When reexpanding, do we always create a new body?
virtual NullablePtr<ASTScopeImpl> getParentOfRescuedScopes();
std::vector<ASTScopeImpl *> rescueScopesToReuse();
void addReusedScopes(ArrayRef<ASTScopeImpl *>);
virtual NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued();
std::vector<ASTScopeImpl *>
rescueASTAncestorScopesForReuseFromMeOrDescendants();
void replaceASTAncestorScopes(ArrayRef<ASTScopeImpl *>);
private:
void removeChildren();
@@ -196,6 +207,8 @@ private:
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
@@ -219,6 +232,12 @@ public:
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
@@ -253,6 +272,8 @@ public:
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;
@@ -314,10 +335,17 @@ public:
/// 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();
virtual bool isCurrent() const;
bool isCurrent() const;
virtual bool isCurrentIfWasExpanded() const;
private:
/// Compare the pre-expasion range with the post-expansion range and return
@@ -328,6 +356,8 @@ 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;
@@ -356,9 +386,6 @@ private:
virtual ScopeCreator &getScopeCreator();
protected:
void setChildrenCountWhenLastExpanded();
#pragma mark - - creation queries
public:
virtual bool isThisAnAbstractStorageDecl() const { return false; }
@@ -506,6 +533,7 @@ public:
/// 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);
@@ -521,7 +549,9 @@ public:
NullablePtr<DeclContext> getDeclContext() const override;
void addNewDeclsToScopeTree();
void buildScopeTreeEagerly();
void buildFullyExpandedTree();
void
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
const SourceFile *getSourceFile() const override;
NullablePtr<const void> addressForPrinting() const override { return SF; }
@@ -552,7 +582,7 @@ public:
void *operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment = alignof(ASTScopeImpl));
void *operator new(size_t Bytes, void *Mem) {
assert(Mem);
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
@@ -575,12 +605,12 @@ public:
virtual const Decl *
getReferrentOfScope(const GenericTypeOrExtensionScope *s) const;
virtual void beCurrent(IterableTypeScope *) const;
virtual bool isCurrent(const IterableTypeScope *) const;
virtual void beCurrent(IterableTypeScope *) const = 0;
virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0;
virtual NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const;
insertionPointForDeferredExpansion(IterableTypeScope *) const = 0;
virtual SourceRange
sourceRangeForDeferredExpansion(const IterableTypeScope *) const;
sourceRangeForDeferredExpansion(const IterableTypeScope *) const = 0;
};
// For the whole Decl scope of a GenericType or an Extension
@@ -601,6 +631,24 @@ public:
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
@@ -639,6 +687,14 @@ public:
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
@@ -655,7 +711,7 @@ public:
bool omitAssertions) const override;
void beCurrent(IterableTypeScope *) const override;
bool isCurrent(const IterableTypeScope *) const override;
bool isCurrentIfWasExpanded(const IterableTypeScope *) const override;
NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
SourceRange
@@ -694,6 +750,17 @@ 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;
@@ -732,6 +799,8 @@ 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;
};
@@ -753,9 +822,11 @@ public:
protected:
void beCurrent() override;
bool isCurrent() const override;
bool isCurrentIfWasExpanded() const override;
public:
void makeWholeCurrent();
bool isWholeCurrent() const;
void makeBodyCurrent();
bool isBodyCurrent() const;
NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override;
@@ -804,6 +875,7 @@ public:
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;
@@ -984,7 +1056,7 @@ public:
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrent() const override;
bool isCurrentIfWasExpanded() const override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
@@ -1000,7 +1072,7 @@ public:
Decl *getDecl() const { return decl; }
static bool isAMethod(const AbstractFunctionDecl *);
NullablePtr<ASTScopeImpl> getParentOfRescuedScopes() override;
NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
@@ -1076,11 +1148,14 @@ public:
/// 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)) {
assert(sourceRangeWhenCreated.isValid());
ASTScopeAssert(sourceRangeWhenCreated.isValid(),
"VarDecls must have ranges to be looked-up");
}
virtual ~AttachedPropertyWrapperScope() {}
@@ -1157,7 +1232,7 @@ public:
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrent() const override;
bool isCurrentIfWasExpanded() const override;
private:
AnnotatedInsertionPoint
@@ -1331,7 +1406,7 @@ public:
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrent() const override;
bool isCurrentIfWasExpanded() const override;
private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
@@ -1402,7 +1477,7 @@ public:
protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override;
bool isCurrent() const override;
bool isCurrentIfWasExpanded() const override;
private:
AnnotatedInsertionPoint
@@ -1420,7 +1495,7 @@ public:
Decl *getDecl() const { return decl; }
NullablePtr<const void> getReferrent() const override;
NullablePtr<ASTScopeImpl> getParentOfRescuedScopes() override;
NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
};
/// The \c _@specialize attribute.

View File

@@ -592,9 +592,11 @@ class ASTScope {
public:
ASTScope(SourceFile *);
/// Cannot be lazy during type-checking because it mutates the AST.
/// So build eagerly before type-checking
void buildScopeTreeEagerly();
void
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
/// Flesh out the tree for dumping
void buildFullyExpandedTree();
/// \return the scopes traversed
static llvm::SmallVector<const ast_scope::ASTScopeImpl *, 0>

View File

@@ -252,7 +252,7 @@ namespace swift {
bool DisableParserLookup = false;
/// Should we compare to ASTScope-based resolution for debugging?
bool CompareToASTScopeLookup = false;
bool CrosscheckUnqualifiedLookup = false;
/// Should we stress ASTScope-based resolution for debugging?
bool StressASTScopeLookup = false;

View File

@@ -122,8 +122,8 @@ def disable_target_os_checking :
Flag<["-"], "disable-target-os-checking">,
HelpText<"Disable checking the target OS of serialized modules">;
def compare_to_astscope_lookup : Flag<["-"], "compare-to-astscope-lookup">,
HelpText<"Compare legacy to ASTScope-based unqualified name lookup (for debugging)">;
def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup">,
HelpText<"Compare legacy DeclContext- to ASTScope-based unqualified name lookup (for debugging)">;
def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">,
HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">;

View File

@@ -179,7 +179,7 @@ NullablePtr<DeclContext> BraceStmtScope::getDeclContext() const {
NullablePtr<DeclContext>
DefaultArgumentInitializerScope::getDeclContext() const {
auto *dc = decl->getDefaultArgumentInitContext();
assert(dc && "If scope exists, this must exist");
ASTScopeAssert(dc, "If scope exists, this must exist");
return dc;
}
@@ -268,6 +268,9 @@ ExtensionScope::getCorrespondingNominalTypeDecl() const {
void ASTScopeImpl::preOrderDo(function_ref<void(ASTScopeImpl *)> fn) {
fn(this);
preOrderChildrenDo(fn);
}
void ASTScopeImpl::preOrderChildrenDo(function_ref<void(ASTScopeImpl *)> fn) {
for (auto *child : getChildren())
child->preOrderDo(fn);
}
@@ -286,3 +289,22 @@ const StmtConditionElement &
ConditionalClauseScope::getStmtConditionElement() const {
return getCond()[index];
}
unsigned ASTScopeImpl::countDescendants() const {
unsigned count = 0;
const_cast<ASTScopeImpl *>(this)->preOrderDo(
[&](ASTScopeImpl *) { ++count; });
return count - 1;
}
// Can fail if a subscope is lazy and not reexpanded
void ASTScopeImpl::assertThatTreeDoesNotShrink(function_ref<void()> fn) {
#ifndef NDEBUG
unsigned beforeCount = countDescendants();
#endif
fn();
#ifndef NDEBUG
unsigned afterCount = countDescendants();
ASTScopeAssert(beforeCount <= afterCount, "shrank?!");
#endif
}

View File

@@ -186,27 +186,9 @@ class ScopeCreator final {
/// For allocating scopes.
ASTContext &ctx;
public:
/// Because type checking can mutate the AST, eagerly build the tree, then
/// freeze it
enum class Temperature {
Warm, // Can be lazy
Freezing, // Should expand everything eagerly
Frozen // No more changes, except when Decls are added to the source file
};
private:
/// Because type checking can mutate the AST, eagerly build the tree, then
/// freeze it
Temperature temperature = Temperature::Warm;
public:
ASTSourceFileScope *const sourceFileScope;
ASTContext &getASTContext() const { return ctx; }
bool getIsFrozen() const { return temperature == Temperature::Frozen; }
bool getIsFreezing() const { return temperature == Temperature::Freezing; }
void beFreezing() { temperature = Temperature::Freezing; }
void beFrozen() { temperature = Temperature::Frozen; }
/// The AST can have duplicate nodes, and we don't want to create scopes for
/// those.
@@ -223,15 +205,25 @@ public:
/// Given an array of ASTNodes or Decl pointers, add them
/// Return the resultant insertionPoint
ASTScopeImpl *addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint,
ArrayRef<ASTNode> nodesOrDeclsToAdd) {
ASTScopeImpl *
addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint,
ASTScopeImpl *const organicInsertionPoint,
ArrayRef<ASTNode> nodesOrDeclsToAdd) {
auto *ip = insertionPoint;
for (auto nd : expandIfConfigClausesThenCullAndSortElementsOrMembers(
nodesOrDeclsToAdd)) {
if (shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd))
ip = addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip);
else
if (!shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd)) {
// FIXME: Could the range get lost if the node is ever reexpanded?
ip->widenSourceRangeForIgnoredASTNode(nd);
} else {
const unsigned preCount = ip->getChildren().size();
auto *const newIP =
addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip);
if (ip != organicInsertionPoint)
ip->increaseASTAncestorScopeCount(ip->getChildren().size() -
preCount);
ip = newIP;
}
}
return ip;
}
@@ -301,9 +293,9 @@ public:
// IDE/complete_property_delegate_attribute.swift fails because we try to
// expand a member whose source range is backwards.
(void)SM;
assert((d->getStartLoc().isInvalid() ||
!SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc())) &&
"end-before-start will break tree search via location");
ASTScopeAssert(d->getStartLoc().isInvalid() ||
!SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc()),
"end-before-start will break tree search via location");
return true;
}
@@ -314,8 +306,8 @@ public:
template <typename Scope, typename... Args>
ASTScopeImpl *constructExpandAndInsertUncheckable(ASTScopeImpl *parent,
Args... args) {
assert(!Scope(args...).getReferrent() &&
"Not checking for duplicate ASTNode but class supports it");
ASTScopeAssert(!Scope(args...).getReferrent(),
"Not checking for duplicate ASTNode but class supports it");
return constructExpandAndInsert<Scope>(parent, args...);
}
@@ -323,8 +315,9 @@ public:
NullablePtr<ASTScopeImpl>
ifUniqueConstructExpandAndInsert(ASTScopeImpl *parent, Args... args) {
Scope dryRun(args...);
assert(dryRun.getReferrent() &&
"Checking for duplicate ASTNode but class does not support it");
ASTScopeAssert(
dryRun.getReferrent(),
"Checking for duplicate ASTNode but class does not support it");
if (scopedNodes.insert(&dryRun))
return constructExpandAndInsert<Scope>(parent, args...);
return nullptr;
@@ -335,7 +328,7 @@ public:
Args... args) {
if (auto s = ifUniqueConstructExpandAndInsert<Scope>(parent, args...))
return s.get();
llvm_unreachable("Scope should have been unique");
ASTScope_unreachable("Scope should have been unique");
}
private:
@@ -348,8 +341,8 @@ private:
return ip;
}
ASTScopeImpl *insertionPoint = child->expandAndBeCurrent(*this);
assert(child->verifyThatThisNodeComeAfterItsPriorSibling() &&
"Ensure search will work");
ASTScopeAssert(child->verifyThatThisNodeComeAfterItsPriorSibling(),
"Ensure search will work");
return insertionPoint;
}
@@ -388,6 +381,7 @@ private:
// A safe way to discover this, without creating a circular request.
// Cannot call getAttachedPropertyWrappers.
// rdar://55263708
static bool hasAttachedPropertyWrapper(VarDecl *vd) {
return AttachedPropertyWrapperScope::getSourceRangeOfVarDecl(vd).isValid();
}
@@ -489,9 +483,8 @@ private:
expansion.push_back(cond);
if (clause.isActive) {
// rdar://53922172
assert(isInAnActiveNode && "Clause should not be marked "
"active unless it's context is "
"active");
ASTScopeAssert(isInAnActiveNode, "Clause should not be marked active "
"unless it's context is active");
// get inactive nodes that nest in active clauses
for (auto n : clause.Elements) {
if (auto *const d = n.dyn_cast<Decl *>())
@@ -514,8 +507,9 @@ private:
// When working on rdar://53971116 may have to cull more.
std::vector<ASTNode> culled;
llvm::copy_if(input, std::back_inserter(culled), [&](ASTNode n) {
assert(!n.isDecl(DeclKind::Accessor) &&
"Should not find accessors in iterable types or brace statements");
ASTScopeAssert(
!n.isDecl(DeclKind::Accessor),
"Should not find accessors in iterable types or brace statements");
return isLocalizable(n) && !n.isDecl(DeclKind::Var) &&
!n.isDecl(DeclKind::EnumCase);
});
@@ -578,13 +572,13 @@ private:
dumpPBD(pbd, "prev");
if (auto *pbd = dyn_cast<PatternBindingDecl>(d)) {
dumpPBD(pbd, "curr");
llvm_unreachable("found colliding pattern binding decls");
ASTScope_unreachable("found colliding pattern binding decls");
}
llvm::errs() << "Two same kind decls at same loc: \n";
lastD->dump(llvm::errs());
llvm::errs() << "and\n";
d->dump(llvm::errs());
llvm_unreachable("Two same kind decls; unexpected kinds");
ASTScope_unreachable("Two same kind decls; unexpected kinds");
}
}
@@ -618,7 +612,8 @@ private:
dumpRangeable(n2, llvm::errs());
}
#endif
assert(startOrder * endOrder != -1 && "Start order contradicts end order");
ASTScopeAssert(startOrder * endOrder != -1,
"Start order contradicts end order");
return startOrder + endOrder < 1;
}
@@ -637,18 +632,18 @@ public:
// they get created directly by the pattern code.
// Doing otherwise distorts the source range
// of their parents.
assert(!n.isDecl(DeclKind::Accessor) && "Should not see accessors here");
ASTScopeAssert(!n.isDecl(DeclKind::Accessor),
"Should not see accessors here");
// Can occur in illegal code
if (auto *const s = n.dyn_cast<Stmt *>()) {
if (auto *const bs = dyn_cast<BraceStmt>(s))
assert(bs->getNumElements() == 0 && "Might mess up insertion point");
ASTScopeAssert(bs->getNumElements() == 0,
"Might mess up insertion point");
}
return !n.isDecl(DeclKind::Var);
}
bool shouldBeLazy() const {
return !getIsFreezing() && ctx.LangOpts.LazyASTScopes;
}
bool shouldBeLazy() const { return ctx.LangOpts.LazyASTScopes; }
public:
/// For debugging. Return true if scope tree contains all the decl contexts in
@@ -658,11 +653,9 @@ public:
auto allDeclContexts = findLocalizableDeclContextsInAST();
llvm::DenseMap<const DeclContext *, const ASTScopeImpl *> bogusDCs;
bool rebuilt = false;
if (!getIsFrozen()) {
sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) {
rebuilt |= scope->reexpandIfObsolete(*this);
});
}
sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) {
rebuilt |= scope->reexpandIfObsolete(*this);
});
sourceFileScope->postOrderDo([&](ASTScopeImpl *scope) {
if (auto *dc = scope->getDeclContext().getPtrOrNull()) {
auto iter = allDeclContexts.find(dc);
@@ -731,7 +724,7 @@ public:
void *operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment = alignof(ScopeCreator));
void *operator new(size_t Bytes, void *Mem) {
assert(Mem);
ASTScopeAssert(Mem, "Allocation failed");
return Mem;
}
};
@@ -742,36 +735,46 @@ public:
ASTScope::ASTScope(SourceFile *SF) : impl(createScopeTree(SF)) {}
void ASTScope::buildScopeTreeEagerly() {
impl->buildScopeTreeEagerly();
void ASTScope::buildFullyExpandedTree() { impl->buildFullyExpandedTree(); }
void ASTScope::
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() {
impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
}
ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) {
ScopeCreator *scopeCreator = new (SF->getASTContext()) ScopeCreator(SF);
scopeCreator->sourceFileScope->addNewDeclsToScopeTree();
return scopeCreator->sourceFileScope;
}
void ASTSourceFileScope::buildScopeTreeEagerly() {
scopeCreator->beFreezing();
// Eagerly expand any decls already in the tree.
preOrderDo([&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); });
void ASTSourceFileScope::buildFullyExpandedTree() {
addNewDeclsToScopeTree();
preOrderChildrenDo(
[&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); });
}
void ASTSourceFileScope::
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() {
addNewDeclsToScopeTree();
scopeCreator->beFrozen();
}
void ASTSourceFileScope::addNewDeclsToScopeTree() {
assert(SF && scopeCreator);
ASTScopeAssert(SF && scopeCreator,
"Must already have a SourceFile and a ScopeCreator.");
ArrayRef<Decl *> decls = SF->Decls;
// Assume that decls are only added at the end, in source order
ArrayRef<Decl *> newDecls = decls.slice(numberOfDeclsAlreadySeen);
std::vector<ASTNode> newNodes(newDecls.begin(), newDecls.end());
insertionPoint =
scopeCreator->addSiblingsToScopeTree(insertionPoint, newNodes);
scopeCreator->addSiblingsToScopeTree(insertionPoint, this, newNodes);
// TODO: use regular expansion machinery for ASTSourceFileScope
// rdar://55562483
numberOfDeclsAlreadySeen = SF->Decls.size();
setWasExpanded();
// Too slow to perform all the time:
// assert(scopeCreator->containsAllDeclContextsFromAST() &&
// ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(),
// "ASTScope tree missed some DeclContexts or made some up");
}
@@ -897,7 +900,7 @@ public:
#pragma mark special-case creation
ASTScopeImpl *visitSourceFile(SourceFile *, ASTScopeImpl *, ScopeCreator &) {
llvm_unreachable("SourceFiles are orphans.");
ASTScope_unreachable("SourceFiles are orphans.");
}
NullablePtr<ASTScopeImpl> visitYieldStmt(YieldStmt *ys, ASTScopeImpl *p,
@@ -975,8 +978,9 @@ public:
NullablePtr<ASTScopeImpl> visitIfConfigDecl(IfConfigDecl *icd,
ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
llvm_unreachable("Should be handled inside of "
"expandIfConfigClausesThenCullAndSortElementsOrMembers");
ASTScope_unreachable(
"Should be handled inside of "
"expandIfConfigClausesThenCullAndSortElementsOrMembers");
}
NullablePtr<ASTScopeImpl> visitReturnStmt(ReturnStmt *rs, ASTScopeImpl *p,
@@ -1058,12 +1062,9 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) {
haveAddedCleanup = true;
}
storedChildren.push_back(child);
assert(!child->getParent() && "child should not already have parent");
ASTScopeAssert(!child->getParent(), "child should not already have parent");
child->parent = this;
clearCachedSourceRangesOfMeAndAncestors();
// It's possible that some callees do lookups back into the tree.
// So make sure childrenCountWhenLastExpanded is up to date.
setChildrenCountWhenLastExpanded();
}
void ASTScopeImpl::removeChildren() {
@@ -1085,11 +1086,17 @@ void ASTScopeImpl::disownDescendants(ScopeCreator &scopeCreator) {
ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
auto *insertionPoint = expandSpecifically(scopeCreator);
if (scopeCreator.shouldBeLazy()) {
assert(!insertionPointForDeferredExpansion() ||
insertionPointForDeferredExpansion().get() == insertionPoint);
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.");
}
setWasExpanded();
beCurrent();
assert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()));
ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()),
"Bad range.");
return insertionPoint;
}
@@ -1179,9 +1186,9 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
// we cannot make a scope for it, since no source range.
if (patternEntry.getOriginalInit() &&
isLocalizable(patternEntry.getOriginalInit())) {
assert(
ASTScopeAssert(
!getSourceManager().isBeforeInBuffer(
patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()) &&
patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()),
"Original inits are always after the '='");
scopeCreator
.constructExpandAndInsertUncheckable<PatternEntryInitializerScope>(
@@ -1191,8 +1198,8 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
forEachVarDeclWithLocalizableAccessors(scopeCreator, [&](VarDecl *var) {
scopeCreator.ifUniqueConstructExpandAndInsert<VarDeclScope>(this, var);
});
assert(!handleUseBeforeDef &&
"next line is wrong otherwise; would need a use scope");
ASTScopeAssert(!handleUseBeforeDef,
"next line is wrong otherwise; would need a use scope");
return {getParent().get(), "When not handling use-before-def, succeeding "
"code just goes in the same scope as this one"};
@@ -1230,7 +1237,7 @@ ConditionalClauseScope::expandAScopeThatCreatesANewInsertionPoint(
return {ccPatternUseScope,
"Succeeding code must be in scope of conditional variables"};
}
llvm_unreachable("Unhandled StmtConditionKind in switch");
ASTScope_unreachable("Unhandled StmtConditionKind in switch");
}
AnnotatedInsertionPoint
@@ -1263,7 +1270,7 @@ BraceStmtScope::expandAScopeThatCreatesANewInsertionPoint(
ScopeCreator &scopeCreator) {
// TODO: remove the sort after performing rdar://53254395
auto *insertionPoint =
scopeCreator.addSiblingsToScopeTree(this, stmt->getElements());
scopeCreator.addSiblingsToScopeTree(this, this, stmt->getElements());
if (auto *s = scopeCreator.getASTContext().Stats)
++s->getFrontendCounters().NumBraceStmtASTScopeExpansions;
return {
@@ -1289,7 +1296,7 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
void ASTSourceFileScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
llvm_unreachable("expanded by addNewDeclsToScopeTree()");
ASTScope_unreachable("expanded by addNewDeclsToScopeTree()");
}
// Create child scopes for every declaration in a body.
@@ -1484,7 +1491,8 @@ void DefaultArgumentInitializerScope::
expandAScopeThatDoesNotCreateANewInsertionPoint(
ScopeCreator &scopeCreator) {
auto *initExpr = decl->getDefaultValue();
assert(initExpr);
ASTScopeAssert(initExpr,
"Default argument initializer must have an initializer.");
scopeCreator.addToScopeTree(initExpr, this);
}
@@ -1599,8 +1607,8 @@ AbstractPatternEntryScope::AbstractPatternEntryScope(
PatternBindingDecl *declBeingScoped, unsigned entryIndex,
DeclVisibilityKind vis)
: decl(declBeingScoped), patternEntryIndex(entryIndex), vis(vis) {
assert(entryIndex < declBeingScoped->getPatternList().size() &&
"out of bounds");
ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(),
"out of bounds");
}
void AbstractPatternEntryScope::forEachVarDeclWithLocalizableAccessors(
@@ -1649,7 +1657,8 @@ bool ASTScopeImpl::isATypeDeclScope() const {
void ScopeCreator::forEachClosureIn(
Expr *expr, function_ref<void(NullablePtr<CaptureListExpr>, ClosureExpr *)>
foundClosure) {
assert(expr);
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 {
@@ -1720,7 +1729,7 @@ void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {}
void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
auto nodes = asNodeVector(getIterableDeclContext().get()->getMembers());
scopeCreator.addSiblingsToScopeTree(this, nodes);
scopeCreator.addSiblingsToScopeTree(this, this, nodes);
if (auto *s = scopeCreator.getASTContext().Stats)
++s->getFrontendCounters().NumIterableTypeBodyASTScopeExpansions;
}
@@ -1728,19 +1737,22 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
#pragma mark - reexpandIfObsolete
bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) {
if (scopeCreator.getIsFrozen() ||
(isCurrent() &&
!scopeCreator.getASTContext().LangOpts.StressASTScopeLookup))
if (isCurrent() &&
!scopeCreator.getASTContext().LangOpts.StressASTScopeLookup) {
ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded.");
return false;
}
reexpand(scopeCreator);
return true;
}
void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) {
auto scopesToReuse = rescueScopesToReuse();
auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants();
disownDescendants(scopeCreator);
// If the expansion recurses back into the tree for lookup, the ASTAncestor
// scopes will have already been rescued and won't be found! HERE
expandAndBeCurrent(scopeCreator);
addReusedScopes(scopesToReuse);
replaceASTAncestorScopes(astAncestorScopes);
}
#pragma mark getScopeCreator
@@ -1800,8 +1812,15 @@ NullablePtr<ASTScopeImpl>
IterableTypeScope::insertionPointForDeferredExpansion() {
return portion->insertionPointForDeferredExpansion(this);
}
NullablePtr<ASTScopeImpl>
Portion::insertionPointForDeferredExpansion(IterableTypeScope *) const {
GenericTypeOrExtensionWholePortion::insertionPointForDeferredExpansion(
IterableTypeScope *s) const {
return s->getParent().get();
}
NullablePtr<ASTScopeImpl>
GenericTypeOrExtensionWherePortion::insertionPointForDeferredExpansion(
IterableTypeScope *) const {
return nullptr;
}
NullablePtr<ASTScopeImpl>
@@ -1810,23 +1829,46 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion(
return s->getParent().get();
}
bool ASTScopeImpl::isCurrent() const {
return getWasExpanded() && isCurrentIfWasExpanded();
}
void ASTScopeImpl::beCurrent() {}
bool ASTScopeImpl::isCurrent() const { return true; }
bool ASTScopeImpl::isCurrentIfWasExpanded() const { return true; }
void IterableTypeScope::beCurrent() { portion->beCurrent(this); }
bool IterableTypeScope::isCurrent() const { return portion->isCurrent(this); }
void Portion::beCurrent(IterableTypeScope *) const {}
bool Portion::isCurrent(const IterableTypeScope *) const { return true; }
bool IterableTypeScope::isCurrentIfWasExpanded() const {
return portion->isCurrentIfWasExpanded(this);
}
void GenericTypeOrExtensionWholePortion::beCurrent(IterableTypeScope *s) const {
s->makeWholeCurrent();
}
bool GenericTypeOrExtensionWholePortion::isCurrentIfWasExpanded(
const IterableTypeScope *s) const {
return s->isWholeCurrent();
}
void GenericTypeOrExtensionWherePortion::beCurrent(IterableTypeScope *) const {}
bool GenericTypeOrExtensionWherePortion::isCurrentIfWasExpanded(
const IterableTypeScope *) const {
return true;
}
void IterableTypeBodyPortion::beCurrent(IterableTypeScope *s) const {
s->makeBodyCurrent();
}
bool IterableTypeBodyPortion::isCurrent(const IterableTypeScope *s) const {
bool IterableTypeBodyPortion::isCurrentIfWasExpanded(
const IterableTypeScope *s) const {
return s->isBodyCurrent();
}
void IterableTypeScope::makeWholeCurrent() {
ASTScopeAssert(getWasExpanded(), "Should have been expanded");
}
bool IterableTypeScope::isWholeCurrent() const {
// Whole starts out unexpanded, and is lazily built but will have at least a
// body scope child
return getWasExpanded();
}
void IterableTypeScope::makeBodyCurrent() {
memberCount = getIterableDeclContext().get()->getMemberCount();
}
@@ -1837,13 +1879,12 @@ bool IterableTypeScope::isBodyCurrent() const {
void AbstractFunctionBodyScope::beCurrent() {
bodyWhenLastExpanded = decl->getBody(false);
}
bool AbstractFunctionBodyScope::isCurrent() const {
bool AbstractFunctionBodyScope::isCurrentIfWasExpanded() const {
return bodyWhenLastExpanded == decl->getBody(false);
;
}
void TopLevelCodeScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(); }
bool TopLevelCodeScope::isCurrent() const {
bool TopLevelCodeScope::isCurrentIfWasExpanded() const {
return bodyWhenLastExpanded == decl->getBody();
}
@@ -1862,11 +1903,12 @@ void PatternEntryDeclScope::beCurrent() {
return;
varCountWhenLastExpanded = countVars(getPatternEntry());
}
bool PatternEntryDeclScope::isCurrent() const {
bool PatternEntryDeclScope::isCurrentIfWasExpanded() const {
if (initWhenLastExpanded != getPatternEntry().getOriginalInit())
return false;
if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) {
assert(varCountWhenLastExpanded == countVars(getPatternEntry()));
ASTScopeAssert(varCountWhenLastExpanded == countVars(getPatternEntry()),
"Vars were not supposed to be added to a pattern entry.");
return true;
}
return countVars(getPatternEntry()) == varCountWhenLastExpanded;
@@ -1875,62 +1917,69 @@ bool PatternEntryDeclScope::isCurrent() const {
void WholeClosureScope::beCurrent() {
bodyWhenLastExpanded = closureExpr->getBody();
}
bool WholeClosureScope::isCurrent() const {
bool WholeClosureScope::isCurrentIfWasExpanded() const {
return bodyWhenLastExpanded == closureExpr->getBody();
}
#pragma mark getParentOfRescuedScopes
NullablePtr<ASTScopeImpl> ASTScopeImpl::getParentOfRescuedScopes() {
#pragma mark getParentOfASTAncestorScopesToBeRescued
NullablePtr<ASTScopeImpl>
ASTScopeImpl::getParentOfASTAncestorScopesToBeRescued() {
return this;
}
NullablePtr<ASTScopeImpl>
AbstractFunctionBodyScope::getParentOfRescuedScopes() {
AbstractFunctionBodyScope::getParentOfASTAncestorScopesToBeRescued() {
// Reexpansion always creates a new body as the first child
// That body contains the scopes to be rescued.
return getChildren().empty() ? nullptr : getChildren().front();
}
NullablePtr<ASTScopeImpl> TopLevelCodeScope::getParentOfRescuedScopes() {
NullablePtr<ASTScopeImpl>
TopLevelCodeScope::getParentOfASTAncestorScopesToBeRescued() {
// Reexpansion always creates a new body as the first child
// That body contains the scopes to be rescued.
return getChildren().empty() ? nullptr : getChildren().front();
}
#pragma mark rescuing & reusing
std::vector<ASTScopeImpl *> ASTScopeImpl::rescueScopesToReuse() {
if (auto *p = getParentOfRescuedScopes().getPtrOrNull()) {
return p->rescueYoungestChildren(p->getChildren().size() -
p->childrenCountWhenLastExpanded);
std::vector<ASTScopeImpl *>
ASTScopeImpl::rescueASTAncestorScopesForReuseFromMeOrDescendants() {
if (auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull()) {
return p->rescueASTAncestorScopesForReuseFromMe();
}
ASTScopeAssert(
getASTAncestorScopeCount() == 0,
"If receives ASTAncestor scopes, must know where to find parent");
return {};
}
void ASTScopeImpl::addReusedScopes(ArrayRef<ASTScopeImpl *> scopesToAdd) {
auto *p = getParentOfRescuedScopes().getPtrOrNull();
void ASTScopeImpl::replaceASTAncestorScopes(
ArrayRef<ASTScopeImpl *> scopesToAdd) {
auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull();
if (!p) {
assert(scopesToAdd.empty() && "Non-empty body disappeared?!");
ASTScopeAssert(scopesToAdd.empty(), "Non-empty body disappeared?!");
return;
}
auto &ctx = getASTContext();
for (auto *s : scopesToAdd) {
p->addChild(s, ctx);
assert(s->verifyThatThisNodeComeAfterItsPriorSibling() &&
"Ensure search will work");
ASTScopeAssert(s->verifyThatThisNodeComeAfterItsPriorSibling(),
"Ensure search will work");
}
p->increaseASTAncestorScopeCount(scopesToAdd.size());
}
std::vector<ASTScopeImpl *>
ASTScopeImpl::rescueYoungestChildren(const unsigned int count) {
std::vector<ASTScopeImpl *> youngestChildren;
for (unsigned i = getChildren().size() - count; i < getChildren().size(); ++i)
youngestChildren.push_back(getChildren()[i]);
ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe() {
std::vector<ASTScopeImpl *> astAncestorScopes;
for (unsigned i = getChildren().size() - getASTAncestorScopeCount();
i < getChildren().size(); ++i)
astAncestorScopes.push_back(getChildren()[i]);
// So they don't get disowned and children cleared.
for (unsigned i = 0; i < count; ++i) {
for (unsigned i = 0; i < getASTAncestorScopeCount(); ++i) {
storedChildren.back()->emancipate();
storedChildren.pop_back();
}
return youngestChildren;
}
void ASTScopeImpl::setChildrenCountWhenLastExpanded() {
childrenCountWhenLastExpanded = getChildren().size();
resetASTAncestorScopeCount();
return astAncestorScopes;
}
bool AbstractFunctionDeclScope::shouldCreateAccessorScope(

View File

@@ -64,6 +64,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
return fileScope; // operators always at file scope
const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr);
ASTScopeAssert(innermost->getWasExpanded(),
"If looking in a scope, it must have been expanded.");
// The legacy lookup code gets passed both a SourceLoc and a starting context.
// However, our ultimate intent is for clients to not have to pass in a
@@ -95,10 +97,12 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
// fileScope->dump();
llvm::errs() << "\n\n";
assert(fileScope->crossCheckWithAST());
// Might distort things
// if (fileScope->crossCheckWithAST())
// llvm::errs() << "Tree creation missed some DeclContexts.\n";
}
assert(startingScope && "ASTScopeImpl: could not find startingScope");
ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope");
return startingScope;
}
@@ -123,7 +127,8 @@ const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const {
const auto r = getSourceRangeOfThisASTNode();
(void)r;
assert(!getSourceManager().isBeforeInBuffer(r.End, r.Start));
ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start),
"Range is backwards.");
return true;
}
@@ -135,12 +140,12 @@ ASTScopeImpl::findChildContaining(SourceLoc loc,
SourceManager &sourceMgr;
bool operator()(const ASTScopeImpl *scope, SourceLoc loc) {
assert(scope->checkSourceRangeOfThisASTNode());
ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End,
loc);
}
bool operator()(SourceLoc loc, const ASTScopeImpl *scope) {
assert(scope->checkSourceRangeOfThisASTNode());
ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(loc,
scope->getSourceRangeOfScope().End);
}
@@ -169,7 +174,7 @@ bool ASTScopeImpl::doesContextMatchStartingContext(
if (auto p = getParent())
return p.get()->doesContextMatchStartingContext(context);
// Topmost scope always has a context, the SourceFile.
llvm_unreachable("topmost scope always has a context, the SourceFile");
ASTScope_unreachable("topmost scope always has a context, the SourceFile");
}
// For a SubscriptDecl with generic parameters, the call tries to do lookups
@@ -383,7 +388,7 @@ bool AbstractFunctionBodyScope::lookupLocalsOrMembers(
bool MethodBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const {
assert(isAMethod(decl));
ASTScopeAssert(isAMethod(decl), "Asking for members of a non-method.");
if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true;
return consumer.consume({decl->getImplicitSelfDecl()},
@@ -392,7 +397,9 @@ bool MethodBodyScope::lookupLocalsOrMembers(
bool PureFunctionBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const {
assert(!isAMethod(decl));
ASTScopeAssert(
!isAMethod(decl),
"Should have called lookupLocalsOrMembers instead of this function.");
if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true;
@@ -491,7 +498,7 @@ bool ASTScopeImpl::lookupLocalBindingsInPattern(Pattern *p,
NullablePtr<DeclContext>
GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC(
ArrayRef<const ASTScopeImpl *> history) {
assert(history.size() != 0 && "includes current scope");
ASTScopeAssert(history.size() != 0, "includes current scope");
size_t i = history.size() - 1; // skip last entry (this scope)
while (i != 0) {
Optional<NullablePtr<DeclContext>> maybeSelfDC =
@@ -632,7 +639,7 @@ Optional<bool> GenericParamScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
if (auto *dc = getDeclContext().getPtrOrNull())
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc);
llvm_unreachable("generic what?");
ASTScope_unreachable("generic what?");
}
Optional<bool> AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope(

View File

@@ -38,6 +38,7 @@ using namespace ast_scope;
static SourceLoc getStartOfFirstParam(ClosureExpr *closure);
static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &,
SourceLoc endLoc);
static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *);
SourceRange ASTScopeImpl::widenSourceRangeForIgnoredASTNodes(
const SourceRange range) const {
@@ -53,7 +54,7 @@ SourceRange
ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range,
const bool omitAssertions) const {
if (getChildren().empty()) {
assert(omitAssertions || range.Start.isValid());
ASTScopeAssert(omitAssertions || range.Start.isValid(), "Bad range.");
return range;
}
const auto childStart =
@@ -61,7 +62,7 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range,
const auto childEnd =
getChildren().back()->getSourceRangeOfScope(omitAssertions).End;
auto childRange = SourceRange(childStart, childEnd);
assert(omitAssertions || childRange.isValid());
ASTScopeAssert(omitAssertions || childRange.isValid(), "Bad range.");
if (range.isInvalid())
return childRange;
@@ -71,12 +72,14 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range,
}
bool ASTScopeImpl::checkSourceRangeAfterExpansion(const ASTContext &ctx) const {
assert((getSourceRangeOfThisASTNode().isValid() || !getChildren().empty()) &&
"need to be able to find source range");
assert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()) &&
"Search will fail");
assert(checkLazySourceRange(ctx) &&
"Lazy scopes must have compatible ranges before and after expansion");
ASTScopeAssert(getSourceRangeOfThisASTNode().isValid() ||
!getChildren().empty(),
"need to be able to find source range");
ASTScopeAssert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()),
"Search will fail");
ASTScopeAssert(
checkLazySourceRange(ctx),
"Lazy scopes must have compatible ranges before and after expansion");
return true;
}
@@ -144,7 +147,7 @@ bool ASTScopeImpl::verifyThatThisNodeComeAfterItsPriorSibling() const {
// .getRangeForBuffer(
// getSourceFile()->getBufferID().getValue())
// .str();
llvm_unreachable("unexpected out-of-order nodes");
ASTScope_unreachable("unexpected out-of-order nodes");
return false;
}
@@ -161,7 +164,7 @@ NullablePtr<ASTScopeImpl> ASTScopeImpl::getPriorSibling() const {
break;
}
}
assert(myIndex != -1 && "I have been disowned!");
ASTScopeAssert(myIndex != -1, "I have been disowned!");
if (myIndex == 0)
return nullptr;
return siblingsAndMe[myIndex - 1];
@@ -263,10 +266,15 @@ SourceRange GenericParamScope::getSourceRangeOfThisASTNode(
// is visible from the start of the body.
if (auto *protoDecl = dyn_cast<ProtocolDecl>(nOrE))
return SourceRange(protoDecl->getBraces().Start, protoDecl->getEndLoc());
auto startLoc = paramList->getSourceRange().Start;
if (startLoc.isInvalid())
startLoc = holder->getStartLoc();
return SourceRange(startLoc, holder->getEndLoc());
const auto startLoc = paramList->getSourceRange().Start;
const auto validStartLoc =
startLoc.isValid() ? startLoc : holder->getStartLoc();
// Since ExtensionScope (whole portion) range doesn't start till after the
// extended nominal, the range here must be pushed back, too.
if (auto const *const ext = dyn_cast<ExtensionDecl>(holder)) {
return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc());
}
return SourceRange(validStartLoc, holder->getEndLoc());
}
SourceRange ASTSourceFileScope::getSourceRangeOfThisASTNode(
@@ -294,12 +302,28 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf(
auto *d = scope->getDecl();
auto r = d->getSourceRangeIncludingAttrs();
if (r.Start.isValid()) {
assert(r.End.isValid());
return r;
ASTScopeAssert(r.End.isValid(), "Start valid imples end valid.");
return scope->moveStartPastExtendedNominal(r);
}
return d->getSourceRange();
}
SourceRange
ExtensionScope::moveStartPastExtendedNominal(const SourceRange sr) const {
const auto start = getLocAfterExtendedNominal(decl);
// Illegal code can have an endLoc that is before the end of the
// ExtendedNominal, so push the end back, too, in that case.
const auto end =
getSourceManager().isBeforeInBuffer(sr.End, start) ? start : sr.End;
return SourceRange(start, end);
}
SourceRange
GenericTypeScope::moveStartPastExtendedNominal(const SourceRange sr) const {
// There is no extended nominal
return sr;
}
SourceRange GenericTypeOrExtensionWherePortion::getChildlessSourceRangeOf(
const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const {
return scope->getGenericContext()->getTrailingWhereClause()->getSourceRange();
@@ -314,7 +338,7 @@ SourceRange IterableTypeBodyPortion::getChildlessSourceRangeOf(
return e->getBraces();
if (omitAssertions)
return SourceRange();
llvm_unreachable("No body!");
ASTScope_unreachable("No body!");
}
SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode(
@@ -323,7 +347,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode(
// them at the start location of the accessor.
auto r = decl->getSourceRangeIncludingAttrs();
if (r.Start.isValid()) {
assert(r.End.isValid());
ASTScopeAssert(r.End.isValid(), "Start valid imples end valid.");
return r;
}
return decl->getBodySourceRange();
@@ -335,9 +359,9 @@ SourceRange ParameterListScope::getSourceRangeOfThisASTNode(
getSourceRangeOfEnclosedParamsOfASTNode(omitAssertions);
auto r = SourceRange(rangeForGoodInput.Start,
fixupEndForBadInput(rangeForGoodInput));
assert(getSourceManager().rangeContains(
getParent().get()->getSourceRangeOfThisASTNode(true), r) &&
"Parameters not within function?!");
ASTScopeAssert(getSourceManager().rangeContains(
getParent().get()->getSourceRangeOfThisASTNode(true), r),
"Parameters not within function?!");
return r;
}
@@ -424,8 +448,8 @@ CaptureListScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
if (!omitAssertions)
assert(closureExpr->getInLoc().isValid() &&
"We don't create these if no in loc");
ASTScopeAssert(closureExpr->getInLoc().isValid(),
"We don't create these if no in loc");
return SourceRange(getStartOfFirstParam(closureExpr),
closureExpr->getInLoc());
}
@@ -459,7 +483,9 @@ ASTScopeImpl::getSourceRangeOfScope(const bool omitAssertions) const {
bool ASTScopeImpl::isSourceRangeCached(const bool omitAssertions) const {
const bool isCached = cachedSourceRange.hasValue();
assert(omitAssertions || isCached || ensureNoAncestorsSourceRangeIsCached());
ASTScopeAssert(omitAssertions || isCached ||
ensureNoAncestorsSourceRangeIsCached(),
"Cached ancestor's range likely is obsolete.");
return isCached;
}
@@ -468,7 +494,7 @@ bool ASTScopeImpl::ensureNoAncestorsSourceRangeIsCached() const {
auto r = !p->isSourceRangeCached(true) &&
p->ensureNoAncestorsSourceRangeIsCached();
if (!r)
llvm_unreachable("found a violation");
ASTScope_unreachable("found a violation");
return true;
}
return true;
@@ -554,8 +580,12 @@ static bool isInterpolatedStringLiteral(const Token& tok) {
Segments.front().Kind != Lexer::StringSegment::Literal;
}
// If right brace is missing, the source range of the body will end
// at the last token, which may be a one of the special cases below.
/// If right brace is missing, the source range of the body will end
/// at the last token, which may be a one of the special cases below.
/// This work is only needed for *unexpanded* scopes because unioning the range
/// with the children will do the same thing for an expanded scope.
/// It is also needed for ignored \c ASTNodes, which may be, e.g. \c
/// InterpolatedStringLiterals
static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &SM,
const SourceLoc endLoc) {
const auto tok = Lexer::getTokenAtLocation(SM, endLoc);
@@ -588,11 +618,33 @@ SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const {
return SourceRange(bsr.Start,
endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral);
}
SourceRange
Portion::sourceRangeForDeferredExpansion(const IterableTypeScope *) const {
SourceRange GenericTypeOrExtensionWholePortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *s) const {
const auto rangeOfThisNodeWithoutChildren =
getChildlessSourceRangeOf(s, false);
const auto rangeExtendedForFinalToken = SourceRange(
rangeOfThisNodeWithoutChildren.Start,
getLocEncompassingPotentialLookups(s->getSourceManager(),
rangeOfThisNodeWithoutChildren.End));
const auto rangePastExtendedNominal =
s->moveStartPastExtendedNominal(rangeExtendedForFinalToken);
return rangePastExtendedNominal;
}
SourceRange GenericTypeOrExtensionWherePortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *) const {
return SourceRange();
}
SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *s) const {
const auto bracesRange = getChildlessSourceRangeOf(s, false);
return SourceRange(bracesRange.Start,
getLocEncompassingPotentialLookups(s->getSourceManager(),
bracesRange.End));
}
SourceRange ASTScopeImpl::getEffectiveSourceRange(const ASTNode n) const {
if (const auto *d = n.dyn_cast<Decl *>())
return d->getSourceRange();
@@ -696,12 +748,11 @@ AbstractFunctionDeclScope::getParmsSourceLocOfAFD(AbstractFunctionDecl *decl) {
// clang-format on
}
#pragma mark deferred scope source ranges
SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *s) const {
const auto bracesRange = getChildlessSourceRangeOf(s, false);
const auto &SM = s->getSourceManager();
return SourceRange(bracesRange.Start,
getLocEncompassingPotentialLookups(SM, bracesRange.End));
SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *const ext) {
const auto *const etr = ext->getExtendedTypeRepr();
if (!etr)
return ext->getStartLoc();
const auto &SM = ext->getASTContext().SourceMgr;
return Lexer::getCharSourceRangeFromSourceRange(SM, etr->getSourceRange())
.getEnd();
}

View File

@@ -227,15 +227,15 @@ namespace {
whereToLook, isCascadingUse.getValueOr(resolution)};
}
};
bool useASTScopesForExperimentalLookup() const;
bool useASTScopesForLookup() const;
/// For testing, assume this lookup is enabled:
bool useASTScopesForExperimentalLookupIfEnabled() const;
bool useASTScopesForLookupIfEnabled() const;
void lookUpTopLevelNamesInModuleScopeContext(DeclContext *);
void experimentallyLookInASTScopes();
void lookInASTScopes();
/// Can lookup stop searching for results, assuming hasn't looked for outer
/// results yet?
@@ -473,7 +473,8 @@ UnqualifiedLookupFactory::UnqualifiedLookupFactory(
void UnqualifiedLookupFactory::performUnqualifiedLookup() {
#ifndef NDEBUG
++lookupCounter;
stopForDebuggingIfStartingTargetLookup(false);
auto localCounter = lookupCounter;
(void)localCounter; // for debugging
#endif
FrontendStatsTracer StatsTracer(Ctx.Stats, "performUnqualifedLookup",
DC->getParentSourceFile());
@@ -482,30 +483,40 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() {
ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{
DC, initialIsCascadingUse};
const bool compareToASTScopes = Ctx.LangOpts.CompareToASTScopeLookup;
if (useASTScopesForExperimentalLookup() && !compareToASTScopes) {
const bool crosscheckUnqualifiedLookup =
Ctx.LangOpts.CrosscheckUnqualifiedLookup;
if (useASTScopesForLookup()) {
static bool haveWarned = false;
if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) {
haveWarned = true;
llvm::errs() << "WARNING: TRYING Scope exclusively\n";
}
experimentallyLookInASTScopes();
return;
lookInASTScopes();
} else {
#ifndef NDEBUG
stopForDebuggingIfStartingTargetLookup(false);
#endif
if (Name.isOperator())
lookupOperatorInDeclContexts(contextAndIsCascadingUse);
else
lookupNamesIntroducedBy(contextAndIsCascadingUse);
}
if (Name.isOperator())
lookupOperatorInDeclContexts(contextAndIsCascadingUse);
else
lookupNamesIntroducedBy(contextAndIsCascadingUse);
if (compareToASTScopes && useASTScopesForExperimentalLookupIfEnabled()) {
if (crosscheckUnqualifiedLookup && useASTScopesForLookupIfEnabled()) {
ResultsVector results;
size_t indexOfFirstOuterResult = 0;
UnqualifiedLookupFactory scopeLookup(Name, DC, Loc, options,
results, indexOfFirstOuterResult);
scopeLookup.experimentallyLookInASTScopes();
assert(verifyEqualTo(std::move(scopeLookup), "UnqualifedLookup",
"Scope lookup"));
UnqualifiedLookupFactory altLookup(Name, DC, Loc, options, results,
indexOfFirstOuterResult);
if (!useASTScopesForLookup())
altLookup.lookInASTScopes();
else if (Name.isOperator())
altLookup.lookupOperatorInDeclContexts(contextAndIsCascadingUse);
else
altLookup.lookupNamesIntroducedBy(contextAndIsCascadingUse);
assert(
verifyEqualTo(std::move(altLookup), "main lookup", "alternate lookup"));
}
}
@@ -530,13 +541,11 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext(
recordCompletionOfAScope();
}
bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookup() const {
return Ctx.LangOpts.EnableASTScopeLookup &&
useASTScopesForExperimentalLookupIfEnabled();
bool UnqualifiedLookupFactory::useASTScopesForLookup() const {
return Ctx.LangOpts.EnableASTScopeLookup && useASTScopesForLookupIfEnabled();
}
bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookupIfEnabled()
const {
bool UnqualifiedLookupFactory::useASTScopesForLookupIfEnabled() const {
if (!Loc.isValid())
return false;
const auto *const SF = DC->getParentSourceFile();
@@ -1098,7 +1107,7 @@ UnqualifiedLookupFactory::ResultFinderForTypeContext::findSelfBounds(
#pragma mark ASTScopeImpl support
void UnqualifiedLookupFactory::experimentallyLookInASTScopes() {
void UnqualifiedLookupFactory::lookInASTScopes() {
ASTScopeDeclConsumerForUnqualifiedLookup consumer(*this);
@@ -1142,7 +1151,7 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume(
// In order to preserve the behavior of the existing context-based lookup,
// which finds all results for non-local variables at the top level instead
// of stopping at the first one, ignore results at the top level that are
// not local variables. The caller \c experimentallyLookInASTScopes will
// not local variables. The caller \c lookInASTScopes will
// then do the appropriate work when the scope lookup fails. In
// FindLocalVal::visitBraceStmt, it sees PatternBindingDecls, not VarDecls,
// so a VarDecl at top level would not be found by the context-based lookup.

View File

@@ -337,7 +337,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Args.hasFlag(options::OPT_enable_astscope_lookup,
options::OPT_disable_astscope_lookup, Opts.EnableASTScopeLookup) ||
Opts.DisableParserLookup;
Opts.CompareToASTScopeLookup |= Args.hasArg(OPT_compare_to_astscope_lookup);
Opts.CrosscheckUnqualifiedLookup |=
Args.hasArg(OPT_crosscheck_unqualified_lookup);
Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup);
Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup);
Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes);

View File

@@ -749,13 +749,16 @@ static void dumpAndPrintScopeMap(CompilerInvocation &Invocation,
if (Invocation.getFrontendOptions().DumpScopeMapLocations.empty()) {
llvm::errs() << "***Complete scope map***\n";
scope.buildFullyExpandedTree();
scope.print(llvm::errs());
return;
}
// Probe each of the locations, and dump what we find.
for (auto lineColumn :
Invocation.getFrontendOptions().DumpScopeMapLocations)
Invocation.getFrontendOptions().DumpScopeMapLocations) {
scope.buildFullyExpandedTree();
scope.dumpOneScopeMapLocation(lineColumn);
}
}
static SourceFile *getPrimaryOrMainSourceFile(CompilerInvocation &Invocation,

View File

@@ -352,12 +352,14 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
if (SF.ASTStage == SourceFile::TypeChecked)
return;
// Eagerly build a scope tree before type checking
// because type-checking mutates the AST and that throws off the scope-based
// lookups.
// Eagerly build the top-level scopes tree before type checking
// because type-checking expressions mutates the AST and that throws off the
// scope-based lookups. Only the top-level scopes because extensions have not
// been bound yet.
if (SF.getASTContext().LangOpts.EnableASTScopeLookup &&
SF.isSuitableForASTScopes())
SF.getScope().buildScopeTreeEagerly();
SF.getScope()
.buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
auto &Ctx = SF.getASTContext();
BufferIndirectlyCausingDiagnosticRAII cpr(SF);

View File

@@ -27,31 +27,36 @@ var i: Int = b.my_identity()
// CHECK-EXPANDED: ***Complete scope map***
// CHECK-EXPANDED-NEXT: ASTSourceFileScope {{.*}}, (uncached) [1:1 - 6{{.*}}:1] 'SOURCE_DIR{{[/\\]}}test{{[/\\]}}NameBinding{{[/\\]}}scope_map_top_level.swift'
// CHECK-EXPANDED-NEXT: |-NominalTypeDeclScope {{.*}}, [4:1 - 4:13]
// CHECK-EXPANDED-NEXT: `-NominalTypeBodyScope {{.*}}, [4:11 - 4:13]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [6:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [6:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-NominalTypeDeclScope {{.*}}, [4:1 - 4:13]
// CHECK-EXPANDED-NEXT: `-NominalTypeBodyScope {{.*}}, [4:11 - 4:13]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [6:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [6:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [6:5 - 6:15] entry 0 'a'
// CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [6:15 - 6:15] entry 0 'a'
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-GuardStmtScope {{.*}}, [8:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-ConditionalClauseScope, [8:7 - 8:22] index 0
// CHECK-EXPANDED-NEXT: `-ConditionalClausePatternUseScope, [8:22 - 8:22] let b?
// CHECK-EXPANDED-NEXT: |-BraceStmtScope {{.*}}, [8:22 - 9:1]
// CHECK-EXPANDED-NEXT: `-LookupParentDiversionScope, [9:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-ConditionalClausePatternUseScope, [8:22 - 8:22] let b{{\??}}
// CHECK-EXPANDED-NEXT: |-BraceStmtScope {{.*}}, [8:22 - 9:1]
// CHECK-EXPANDED-NEXT: `-LookupParentDiversionScope, [9:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-AbstractFunctionDeclScope {{.*}}, [11:1 - 11:13] 'foo()'
// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [11:9 - 11:13]
// CHECK-EXPANDED-NEXT: `-PureFunctionBodyScope {{.*}}, [11:12 - 11:13]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [13:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [13:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [11:9 - 11:13]
// CHECK-EXPANDED-NEXT: `-PureFunctionBodyScope {{.*}}, [11:12 - 11:13]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [11:12 - 11:13]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [13:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [13:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-PatternEntryDeclScope {{.*}}, [13:5 - 13:9] entry 0 'c'
// CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [13:9 - 13:9] entry 0 'c'
// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15]
// CHECK-EXPANDED-NEXT: |-ExtensionDeclScope {{.*}}, [17:1 - 19:1]
// CHECK-EXPANDED-NEXT: `-ExtensionBodyScope {{.*}}, [17:15 - 19:1]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [21:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [21:1 - 21:28]
// CHECK-EXPANDED-NEXT: |-TypeAliasDeclScope {{.*}}, [15:1 - 15:15]
// CHECK-EXPANDED-NEXT: |-ExtensionDeclScope {{.*}}, [17:14 - 19:1]
// CHECK-EXPANDED-NEXT: `-ExtensionBodyScope {{.*}}, [17:15 - 19:1]
// CHECK-EXPANDED-NEXT: `-AbstractFunctionDeclScope {{.*}}, [18:3 - 18:43] 'my_identity()'
// CHECK-EXPANDED-NEXT: `-ParameterListScope {{.*}}, [18:19 - 18:43]
// CHECK-EXPANDED-NEXT: `-MethodBodyScope {{.*}}, [18:29 - 18:43]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [18:29 - 18:43]
// CHECK-EXPANDED-NEXT: `-TopLevelCodeScope {{.*}}, [21:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-BraceStmtScope {{.*}}, [21:1 - 21:28]
// CHECK-EXPANDED-NEXT: `-PatternEntryDeclScope {{.*}}, [21:5 - 21:28] entry 0 'i'
// CHECK-EXPANDED-NEXT: `-PatternEntryInitializerScope {{.*}}, [21:14 - 21:28] entry 0 'i'