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/STLExtras.h"
#include "llvm/ADT/SmallVector.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 { namespace swift {
#pragma mark Forward-references #pragma mark Forward-references
@@ -125,10 +135,10 @@ private:
/// Must clear source range change whenever this changes /// Must clear source range change whenever this changes
Children storedChildren; Children storedChildren;
/// Because expansion returns an insertion point, bool wasExpanded = false;
/// if a scope is reexpanded, the children added NOT by expansion must be
/// rescued and reused. /// For use-before-def, ASTAncestor scopes may be added to a BraceStmt.
unsigned childrenCountWhenLastExpanded = 0; unsigned astAncestorScopeCount = 0;
/// Can clear storedChildren, so must remember this /// Can clear storedChildren, so must remember this
bool haveAddedCleanup = false; bool haveAddedCleanup = false;
@@ -162,7 +172,7 @@ public:
void *operator new(size_t bytes, const ASTContext &ctx, void *operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment = alignof(ASTScopeImpl)); unsigned alignment = alignof(ASTScopeImpl));
void *operator new(size_t Bytes, void *Mem) { void *operator new(size_t Bytes, void *Mem) {
assert(Mem); ASTScopeAssert(Mem, "Allocation failed");
return Mem; return Mem;
} }
@@ -180,12 +190,13 @@ protected:
public: // for addReusedBodyScopes public: // for addReusedBodyScopes
void addChild(ASTScopeImpl *child, ASTContext &); void addChild(ASTScopeImpl *child, ASTContext &);
std::vector<ASTScopeImpl *> rescueYoungestChildren(unsigned count); std::vector<ASTScopeImpl *> rescueASTAncestorScopesForReuseFromMe();
/// When reexpanding, do we always create a new body? /// When reexpanding, do we always create a new body?
virtual NullablePtr<ASTScopeImpl> getParentOfRescuedScopes(); virtual NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued();
std::vector<ASTScopeImpl *> rescueScopesToReuse(); std::vector<ASTScopeImpl *>
void addReusedScopes(ArrayRef<ASTScopeImpl *>); rescueASTAncestorScopesForReuseFromMeOrDescendants();
void replaceASTAncestorScopes(ArrayRef<ASTScopeImpl *>);
private: private:
void removeChildren(); void removeChildren();
@@ -196,6 +207,8 @@ private:
public: public:
void preOrderDo(function_ref<void(ASTScopeImpl *)>); void preOrderDo(function_ref<void(ASTScopeImpl *)>);
/// Like preorderDo but without myself.
void preOrderChildrenDo(function_ref<void(ASTScopeImpl *)>);
void postOrderDo(function_ref<void(ASTScopeImpl *)>); void postOrderDo(function_ref<void(ASTScopeImpl *)>);
#pragma mark - source ranges #pragma mark - source ranges
@@ -219,6 +232,12 @@ public:
bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "", bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "",
StringRef className = ""); 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: private:
SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const; SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const;
SourceRange SourceRange
@@ -253,6 +272,8 @@ public:
void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref<void()>); void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref<void()>);
public: // public for debugging public: // public for debugging
/// Returns source range of this node alone, without factoring in any
/// children.
virtual SourceRange virtual SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0; getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0;
@@ -314,10 +335,17 @@ public:
/// Return the scope into which to place subsequent decls /// Return the scope into which to place subsequent decls
ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); ASTScopeImpl *expandAndBeCurrent(ScopeCreator &);
unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; }
bool getWasExpanded() const { return wasExpanded; }
protected: protected:
void resetASTAncestorScopeCount() { astAncestorScopeCount = 0; }
void increaseASTAncestorScopeCount(unsigned c) { astAncestorScopeCount += c; }
void setWasExpanded() { wasExpanded = true; }
virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0;
virtual void beCurrent(); virtual void beCurrent();
virtual bool isCurrent() const; bool isCurrent() const;
virtual bool isCurrentIfWasExpanded() const;
private: private:
/// Compare the pre-expasion range with the post-expansion range and return /// Compare the pre-expasion range with the post-expansion range and return
@@ -328,6 +356,8 @@ public:
/// Some scopes can be expanded lazily. /// Some scopes can be expanded lazily.
/// Such scopes must: not change their source ranges after expansion, and /// Such scopes must: not change their source ranges after expansion, and
/// their expansion must return an insertion point outside themselves. /// 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 NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion();
virtual SourceRange sourceRangeForDeferredExpansion() const; virtual SourceRange sourceRangeForDeferredExpansion() const;
@@ -356,9 +386,6 @@ private:
virtual ScopeCreator &getScopeCreator(); virtual ScopeCreator &getScopeCreator();
protected:
void setChildrenCountWhenLastExpanded();
#pragma mark - - creation queries #pragma mark - - creation queries
public: public:
virtual bool isThisAnAbstractStorageDecl() const { return false; } virtual bool isThisAnAbstractStorageDecl() const { return false; }
@@ -506,6 +533,7 @@ public:
/// The number of \c Decls in the \c SourceFile that were already seen. /// The number of \c Decls in the \c SourceFile that were already seen.
/// Since parsing can be interleaved with type-checking, on every /// Since parsing can be interleaved with type-checking, on every
/// lookup, look at creating scopes for any \c Decls beyond this number. /// lookup, look at creating scopes for any \c Decls beyond this number.
/// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded
int numberOfDeclsAlreadySeen = 0; int numberOfDeclsAlreadySeen = 0;
ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator); ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator);
@@ -521,7 +549,9 @@ public:
NullablePtr<DeclContext> getDeclContext() const override; NullablePtr<DeclContext> getDeclContext() const override;
void addNewDeclsToScopeTree(); void addNewDeclsToScopeTree();
void buildScopeTreeEagerly(); void buildFullyExpandedTree();
void
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
const SourceFile *getSourceFile() const override; const SourceFile *getSourceFile() const override;
NullablePtr<const void> addressForPrinting() const override { return SF; } NullablePtr<const void> addressForPrinting() const override { return SF; }
@@ -552,7 +582,7 @@ public:
void *operator new(size_t bytes, const ASTContext &ctx, void *operator new(size_t bytes, const ASTContext &ctx,
unsigned alignment = alignof(ASTScopeImpl)); unsigned alignment = alignof(ASTScopeImpl));
void *operator new(size_t Bytes, void *Mem) { void *operator new(size_t Bytes, void *Mem) {
assert(Mem); ASTScopeAssert(Mem, "Allocation failed");
return Mem; return Mem;
} }
@@ -575,12 +605,12 @@ public:
virtual const Decl * virtual const Decl *
getReferrentOfScope(const GenericTypeOrExtensionScope *s) const; getReferrentOfScope(const GenericTypeOrExtensionScope *s) const;
virtual void beCurrent(IterableTypeScope *) const; virtual void beCurrent(IterableTypeScope *) const = 0;
virtual bool isCurrent(const IterableTypeScope *) const; virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0;
virtual NullablePtr<ASTScopeImpl> virtual NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const; insertionPointForDeferredExpansion(IterableTypeScope *) const = 0;
virtual SourceRange virtual SourceRange
sourceRangeForDeferredExpansion(const IterableTypeScope *) const; sourceRangeForDeferredExpansion(const IterableTypeScope *) const = 0;
}; };
// For the whole Decl scope of a GenericType or an Extension // For the whole Decl scope of a GenericType or an Extension
@@ -601,6 +631,24 @@ public:
const Decl * const Decl *
getReferrentOfScope(const GenericTypeOrExtensionScope *s) const override; 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 /// GenericTypeOrExtension = GenericType or Extension
@@ -639,6 +687,14 @@ public:
SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *,
bool omitAssertions) const override; 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 /// Behavior specific to representing the Body of a NominalTypeDecl or
@@ -655,7 +711,7 @@ public:
bool omitAssertions) const override; bool omitAssertions) const override;
void beCurrent(IterableTypeScope *) const override; void beCurrent(IterableTypeScope *) const override;
bool isCurrent(const IterableTypeScope *) const override; bool isCurrentIfWasExpanded(const IterableTypeScope *) const override;
NullablePtr<ASTScopeImpl> NullablePtr<ASTScopeImpl>
insertionPointForDeferredExpansion(IterableTypeScope *) const override; insertionPointForDeferredExpansion(IterableTypeScope *) const override;
SourceRange SourceRange
@@ -694,6 +750,17 @@ public:
SourceRange SourceRange
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; 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; virtual GenericContext *getGenericContext() const = 0;
std::string getClassName() const override; std::string getClassName() const override;
virtual std::string declKindName() const = 0; virtual std::string declKindName() const = 0;
@@ -732,6 +799,8 @@ class GenericTypeScope : public GenericTypeOrExtensionScope {
public: public:
GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {} GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {}
virtual ~GenericTypeScope() {} virtual ~GenericTypeScope() {}
SourceRange moveStartPastExtendedNominal(SourceRange) const override;
protected: protected:
NullablePtr<const GenericParamList> genericParams() const override; NullablePtr<const GenericParamList> genericParams() const override;
}; };
@@ -753,9 +822,11 @@ public:
protected: protected:
void beCurrent() override; void beCurrent() override;
bool isCurrent() const override; bool isCurrentIfWasExpanded() const override;
public: public:
void makeWholeCurrent();
bool isWholeCurrent() const;
void makeBodyCurrent(); void makeBodyCurrent();
bool isBodyCurrent() const; bool isBodyCurrent() const;
NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override; NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override;
@@ -804,6 +875,7 @@ public:
NullablePtr<NominalTypeDecl> getCorrespondingNominalTypeDecl() const override; NullablePtr<NominalTypeDecl> getCorrespondingNominalTypeDecl() const override;
std::string declKindName() const override { return "Extension"; } std::string declKindName() const override { return "Extension"; }
SourceRange getBraces() const override; SourceRange getBraces() const override;
SourceRange moveStartPastExtendedNominal(SourceRange) const override;
ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent,
ScopeCreator &) override; ScopeCreator &) override;
void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override;
@@ -984,7 +1056,7 @@ public:
protected: protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override; void beCurrent() override;
bool isCurrent() const override; bool isCurrentIfWasExpanded() const override;
private: private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
@@ -1000,7 +1072,7 @@ public:
Decl *getDecl() const { return decl; } Decl *getDecl() const { return decl; }
static bool isAMethod(const AbstractFunctionDecl *); static bool isAMethod(const AbstractFunctionDecl *);
NullablePtr<ASTScopeImpl> getParentOfRescuedScopes() override; NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
protected: protected:
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
@@ -1076,11 +1148,14 @@ public:
/// false positives, that that doesn't hurt anything. However, the result of /// false positives, that that doesn't hurt anything. However, the result of
/// the conservative source range computation doesn't seem to be stable. So /// the conservative source range computation doesn't seem to be stable. So
/// keep the original here, and use it for source range queries. /// keep the original here, and use it for source range queries.
/// rdar://55263708
const SourceRange sourceRangeWhenCreated; const SourceRange sourceRangeWhenCreated;
AttachedPropertyWrapperScope(VarDecl *e) AttachedPropertyWrapperScope(VarDecl *e)
: decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) { : decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) {
assert(sourceRangeWhenCreated.isValid()); ASTScopeAssert(sourceRangeWhenCreated.isValid(),
"VarDecls must have ranges to be looked-up");
} }
virtual ~AttachedPropertyWrapperScope() {} virtual ~AttachedPropertyWrapperScope() {}
@@ -1157,7 +1232,7 @@ public:
protected: protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override; void beCurrent() override;
bool isCurrent() const override; bool isCurrentIfWasExpanded() const override;
private: private:
AnnotatedInsertionPoint AnnotatedInsertionPoint
@@ -1331,7 +1406,7 @@ public:
protected: protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override; void beCurrent() override;
bool isCurrent() const override; bool isCurrentIfWasExpanded() const override;
private: private:
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
@@ -1402,7 +1477,7 @@ public:
protected: protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
void beCurrent() override; void beCurrent() override;
bool isCurrent() const override; bool isCurrentIfWasExpanded() const override;
private: private:
AnnotatedInsertionPoint AnnotatedInsertionPoint
@@ -1420,7 +1495,7 @@ public:
Decl *getDecl() const { return decl; } Decl *getDecl() const { return decl; }
NullablePtr<const void> getReferrent() const override; NullablePtr<const void> getReferrent() const override;
NullablePtr<ASTScopeImpl> getParentOfRescuedScopes() override; NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override;
}; };
/// The \c _@specialize attribute. /// The \c _@specialize attribute.

View File

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

View File

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

View File

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

View File

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

View File

@@ -64,6 +64,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
return fileScope; // operators always at file scope return fileScope; // operators always at file scope
const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); 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. // 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 // However, our ultimate intent is for clients to not have to pass in a
@@ -95,10 +97,12 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
// fileScope->dump(); // fileScope->dump();
llvm::errs() << "\n\n"; 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; return startingScope;
} }
@@ -123,7 +127,8 @@ const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const {
const auto r = getSourceRangeOfThisASTNode(); const auto r = getSourceRangeOfThisASTNode();
(void)r; (void)r;
assert(!getSourceManager().isBeforeInBuffer(r.End, r.Start)); ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start),
"Range is backwards.");
return true; return true;
} }
@@ -135,12 +140,12 @@ ASTScopeImpl::findChildContaining(SourceLoc loc,
SourceManager &sourceMgr; SourceManager &sourceMgr;
bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { bool operator()(const ASTScopeImpl *scope, SourceLoc loc) {
assert(scope->checkSourceRangeOfThisASTNode()); ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End, return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End,
loc); loc);
} }
bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { bool operator()(SourceLoc loc, const ASTScopeImpl *scope) {
assert(scope->checkSourceRangeOfThisASTNode()); ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(loc, return sourceMgr.isBeforeInBuffer(loc,
scope->getSourceRangeOfScope().End); scope->getSourceRangeOfScope().End);
} }
@@ -169,7 +174,7 @@ bool ASTScopeImpl::doesContextMatchStartingContext(
if (auto p = getParent()) if (auto p = getParent())
return p.get()->doesContextMatchStartingContext(context); return p.get()->doesContextMatchStartingContext(context);
// Topmost scope always has a context, the SourceFile. // 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 // For a SubscriptDecl with generic parameters, the call tries to do lookups
@@ -383,7 +388,7 @@ bool AbstractFunctionBodyScope::lookupLocalsOrMembers(
bool MethodBodyScope::lookupLocalsOrMembers( bool MethodBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const { 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)) if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true; return true;
return consumer.consume({decl->getImplicitSelfDecl()}, return consumer.consume({decl->getImplicitSelfDecl()},
@@ -392,7 +397,9 @@ bool MethodBodyScope::lookupLocalsOrMembers(
bool PureFunctionBodyScope::lookupLocalsOrMembers( bool PureFunctionBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const { 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)) if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true; return true;
@@ -491,7 +498,7 @@ bool ASTScopeImpl::lookupLocalBindingsInPattern(Pattern *p,
NullablePtr<DeclContext> NullablePtr<DeclContext>
GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC( GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC(
ArrayRef<const ASTScopeImpl *> history) { 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) size_t i = history.size() - 1; // skip last entry (this scope)
while (i != 0) { while (i != 0) {
Optional<NullablePtr<DeclContext>> maybeSelfDC = Optional<NullablePtr<DeclContext>> maybeSelfDC =
@@ -632,7 +639,7 @@ Optional<bool> GenericParamScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const { Optional<bool> isCascadingUse) const {
if (auto *dc = getDeclContext().getPtrOrNull()) if (auto *dc = getDeclContext().getPtrOrNull())
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc); return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc);
llvm_unreachable("generic what?"); ASTScope_unreachable("generic what?");
} }
Optional<bool> AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope( Optional<bool> AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope(

View File

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

View File

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

View File

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

View File

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

View File

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