Skip to content

Commit cecbf21

Browse files
committed
ASTScope: PatternEntryInitializerScope needs a custom lookup parent
Bindings are not visible from inside their own initializer, eg this is invalid: var (x, y) = (y, x) The PatternEntryDeclScope which starts after the 'var' introduces x and y, and it contains the PatternEntryInitializerScope which starts after the '='. To model this properly in ASTScope, the PatternEntryInitializerScope overrides getLookupParent() to skip the PatternEntryDeclScope that contains it. I believe this is simpler than having PatternEntryDeclScope begin at the source location following the initializer, because it is hard to compute this source location in a way that works with invalid code, for example the 'var' might be nested inside of a BraceStmt with the closing '}' missing.
1 parent 81fc342 commit cecbf21

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

include/swift/AST/ASTScope.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ class ASTScopeImpl {
435435
return p->getParent().isNonNull() ? p : nullptr;
436436
}
437437

438+
public:
438439
/// The tree is organized by source location and for most nodes this is also
439440
/// what obtaines for scoping. However, guards are different. The scope after
440441
/// the guard else must hop into the innermoset scope of the guard condition.
@@ -1094,6 +1095,7 @@ class PatternEntryInitializerScope final : public AbstractPatternEntryScope {
10941095

10951096
protected:
10961097
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
1098+
NullablePtr<const ASTScopeImpl> getLookupParent() const override;
10971099

10981100
private:
10991101
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);

lib/AST/ASTScopeLookup.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,24 @@ bool GenericTypeOrExtensionScope::areMembersVisibleFromWhereClause() const {
271271
return isa<ProtocolDecl>(decl) || isa<ExtensionDecl>(decl);
272272
}
273273

274+
#pragma mark custom lookup parent behavior
275+
276+
NullablePtr<const ASTScopeImpl>
277+
PatternEntryInitializerScope::getLookupParent() const {
278+
auto parent = getParent().get();
279+
assert(parent->getClassName() == "PatternEntryDeclScope");
280+
281+
// Lookups from inside a pattern binding initializer skip the parent
282+
// scope that introduces bindings bound by the pattern, since we
283+
// want this to work:
284+
//
285+
// func f(x: Int) {
286+
// let x = x
287+
// print(x)
288+
// }
289+
return parent->getLookupParent();
290+
}
291+
274292
#pragma mark looking in locals or members - locals
275293

276294
bool GenericParamScope::lookupLocalsOrMembers(DeclConsumer consumer) const {

0 commit comments

Comments
 (0)