mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge remote-tracking branch 'origin/master' into master-next
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)">;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user