Skip to content

Commit 0d90adf

Browse files
committed
[ASTScope] Implement lookup for visible labeled statements.
Use the scope map to implement lookup for the labeled statements that are visible from a given source location, which is a lexical property that is currently handled with stateful tracking in the type checker. For now, merely assert that the results of this approach are identical to the state tracked in the statement type checker.
1 parent 9fd37c9 commit 0d90adf

File tree

5 files changed

+111
-1
lines changed

5 files changed

+111
-1
lines changed

include/swift/AST/ASTScope.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ class ASTScopeImpl {
195195

196196
/// Get ride of descendants and remove them from scopedNodes so the scopes
197197
/// can be recreated. Needed because typechecking inserts a return statment
198-
/// into intiailizers.
198+
/// into initializers.
199199
void disownDescendants(ScopeCreator &);
200200

201201
public: // for addReusedBodyScopes
@@ -415,6 +415,10 @@ class ASTScopeImpl {
415415
unqualifiedLookup(SourceFile *, DeclNameRef, SourceLoc,
416416
const DeclContext *startingContext, DeclConsumer);
417417

418+
/// Entry point into ASTScopeImpl-land for labeled statement lookups.
419+
static llvm::SmallVector<LabeledStmt *, 4>
420+
lookupLabeledStmts(SourceFile *sourceFile, SourceLoc loc);
421+
418422
static Optional<bool>
419423
computeIsCascadingUse(ArrayRef<const ASTScopeImpl *> history,
420424
Optional<bool> initialIsCascadingUse);
@@ -538,6 +542,12 @@ class ASTScopeImpl {
538542

539543
NullablePtr<const ASTScopeImpl>
540544
ancestorWithDeclSatisfying(function_ref<bool(const Decl *)> predicate) const;
545+
546+
/// Whether this scope terminates lookup of labeled statements in the
547+
/// children below it, because one cannot perform a "break" or a "continue"
548+
/// in a child that goes outside of this scope.
549+
virtual bool isLabeledStmtLookupTerminator() const;
550+
541551
}; // end of ASTScopeImpl
542552

543553
#pragma mark - specific scope classes
@@ -1357,6 +1367,9 @@ class ConditionalClauseScope final : public ASTScopeImpl {
13571367
private:
13581368
ArrayRef<StmtConditionElement> getCond() const;
13591369
const StmtConditionElement &getStmtConditionElement() const;
1370+
1371+
protected:
1372+
bool isLabeledStmtLookupTerminator() const override;
13601373
};
13611374

13621375
/// If, while, & guard statements all start with a conditional clause, then some
@@ -1380,6 +1393,7 @@ class ConditionalClausePatternUseScope final : public ASTScopeImpl {
13801393
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
13811394
DeclConsumer) const override;
13821395
void printSpecifics(llvm::raw_ostream &out) const override;
1396+
bool isLabeledStmtLookupTerminator() const override;
13831397
};
13841398

13851399

@@ -1713,6 +1727,9 @@ class AbstractStmtScope : public ASTScopeImpl {
17131727
virtual Stmt *getStmt() const = 0;
17141728
NullablePtr<Stmt> getStmtIfAny() const override { return getStmt(); }
17151729
NullablePtr<const void> getReferrent() const override;
1730+
1731+
protected:
1732+
bool isLabeledStmtLookupTerminator() const override;
17161733
};
17171734

17181735
class LabeledConditionalStmtScope : public AbstractStmtScope {
@@ -1910,6 +1927,7 @@ class ForEachPatternScope final : public ASTScopeImpl {
19101927
protected:
19111928
bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
19121929
DeclConsumer) const override;
1930+
bool isLabeledStmtLookupTerminator() const override;
19131931
};
19141932

19151933
class CaseStmtScope final : public AbstractStmtScope {

include/swift/AST/NameLookup.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,19 @@ class ASTScope {
698698
computeIsCascadingUse(ArrayRef<const ast_scope::ASTScopeImpl *> history,
699699
Optional<bool> initialIsCascadingUse);
700700

701+
/// Entry point to record the visible statement labels from the given
702+
/// point.
703+
///
704+
/// This lookup only considers labels that are visible within the current
705+
/// function, so it will not return any labels from lexical scopes that
706+
/// are not reachable via labeled control flow.
707+
///
708+
/// \returns the set of labeled statements visible from the given source
709+
/// location, with the innermost labeled statement first and proceeding
710+
/// to the outermost labeled statement.
711+
static llvm::SmallVector<LabeledStmt *, 4>
712+
lookupLabeledStmts(SourceFile *sourceFile, SourceLoc loc);
713+
701714
SWIFT_DEBUG_DUMP;
702715
void print(llvm::raw_ostream &) const;
703716
void dumpOneScopeMapLocation(std::pair<unsigned, unsigned>);

lib/AST/ASTScope.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ Optional<bool> ASTScope::computeIsCascadingUse(
5454
return ASTScopeImpl::computeIsCascadingUse(history, initialIsCascadingUse);
5555
}
5656

57+
llvm::SmallVector<LabeledStmt *, 4> ASTScope::lookupLabeledStmts(
58+
SourceFile *sourceFile, SourceLoc loc) {
59+
return ASTScopeImpl::lookupLabeledStmts(sourceFile, loc);
60+
}
61+
5762
#if SWIFT_COMPILER_IS_MSVC
5863
#pragma warning(push)
5964
#pragma warning(disable : 4996)

lib/AST/ASTScopeLookup.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,3 +852,47 @@ bool isLocWithinAnInactiveClause(const SourceLoc loc, SourceFile *SF) {
852852
SF->walk(tester);
853853
return tester.wasFoundWithinInactiveClause;
854854
}
855+
856+
#pragma mark isLabeledStmtLookupTerminator implementations
857+
bool ASTScopeImpl::isLabeledStmtLookupTerminator() const {
858+
return true;
859+
}
860+
861+
bool ConditionalClauseScope::isLabeledStmtLookupTerminator() const {
862+
return false;
863+
}
864+
865+
bool ConditionalClausePatternUseScope::isLabeledStmtLookupTerminator() const {
866+
return false;
867+
}
868+
869+
bool AbstractStmtScope::isLabeledStmtLookupTerminator() const {
870+
return false;
871+
}
872+
873+
bool ForEachPatternScope::isLabeledStmtLookupTerminator() const {
874+
return false;
875+
}
876+
877+
llvm::SmallVector<LabeledStmt *, 4>
878+
ASTScopeImpl::lookupLabeledStmts(SourceFile *sourceFile, SourceLoc loc) {
879+
// Find the innermost scope from which to start our search.
880+
auto *const fileScope = sourceFile->getScope().impl;
881+
const auto *innermost = fileScope->findInnermostEnclosingScope(loc, nullptr);
882+
ASTScopeAssert(innermost->getWasExpanded(),
883+
"If looking in a scope, it must have been expanded.");
884+
885+
llvm::SmallVector<LabeledStmt *, 4> labeledStmts;
886+
for (auto scope = innermost; scope && !scope->isLabeledStmtLookupTerminator();
887+
scope = scope->getParent().getPtrOrNull()) {
888+
// If we have a labeled statement, record it.
889+
if (auto stmt = scope->getStmtIfAny()) {
890+
if (auto labeledStmt = dyn_cast<LabeledStmt>(stmt.get())) {
891+
labeledStmts.push_back(labeledStmt);
892+
continue;
893+
}
894+
}
895+
}
896+
897+
return labeledStmts;
898+
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,36 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
347347
// In any case, remember that we're in this labeled statement so that
348348
// break and continue are aware of it.
349349
SC.ActiveLabeledStmts.push_back(LS);
350+
351+
// Verify that the ASTScope-based query for active labeled statements
352+
// is equivalent to what we have here.
353+
if (LS->getStartLoc().isValid()) {
354+
if (auto sourceFile = SC.DC->getParentSourceFile()) {
355+
// The labeled statements from ASTScope lookup have the
356+
// innermost labeled statement first, so reverse it to
357+
// match the data structure maintained here.
358+
auto activeFromASTScope = ASTScope::lookupLabeledStmts(
359+
sourceFile, LS->getStartLoc());
360+
assert(activeFromASTScope.front() == LS);
361+
std::reverse(activeFromASTScope.begin(), activeFromASTScope.end());
362+
if (activeFromASTScope != SC.ActiveLabeledStmts) {
363+
llvm::errs() << "Old: ";
364+
llvm::interleave(SC.ActiveLabeledStmts, [&](LabeledStmt *LS) {
365+
llvm::errs() << LS;
366+
}, [&] {
367+
llvm::errs() << ' ';
368+
});
369+
llvm::errs() << "\nNew: ";
370+
llvm::interleave(activeFromASTScope, [&](LabeledStmt *LS) {
371+
llvm::errs() << LS;
372+
}, [&] {
373+
llvm::errs() << ' ';
374+
});
375+
llvm::errs() << "\n";
376+
}
377+
assert(activeFromASTScope == SC.ActiveLabeledStmts);
378+
}
379+
}
350380
}
351381
~AddLabeledStmt() {
352382
SC.ActiveLabeledStmts.pop_back();

0 commit comments

Comments
 (0)