[Scope map] A local property name is in scope within its own accessors.

While the use of a local property from within its own accessors is a
bit dubious, Swift 3 only warned on it, so model the existing lookup
behavior in the scope map.
This commit is contained in:
Doug Gregor
2016-09-14 09:16:23 -07:00
parent 40445be66a
commit ac93c52c96
6 changed files with 62 additions and 63 deletions

View File

@@ -1709,7 +1709,10 @@ public:
void setInitContext(DeclContext *dc) { InitContext = dc; }
/// Retrieve the source range covered by this pattern binding.
SourceRange getSourceRange() const;
///
/// \param omitAccessors Whether the computation should omit the accessors
/// from the source range.
SourceRange getSourceRange(bool omitAccessors = false) const;
};
/// \brief This decl contains a pattern and optional initializer for a set

View File

@@ -277,6 +277,18 @@ void ASTScope::expand() const {
return stoleContinuation;
};
// Local function to add the accessors of the variables in the given pattern
// as children.
auto addAccessors = [&](Pattern *pattern) {
// Create children for the accessors of any variables in the pattern that
// have them.
pattern->forEachVariable([&](VarDecl *var) {
if (hasAccessors(var)) {
addChild(new (ctx) ASTScope(this, var));
}
});
};
if (!parentAndExpanded.getInt()) {
// Expand the children in the current scope.
switch (getKind()) {
@@ -365,39 +377,20 @@ void ASTScope::expand() const {
patternBinding.decl->getPatternList()[patternBinding.entry];
// Create a child for the initializer, if present.
ASTScope *initChild = nullptr;
if (patternEntry.getInitAsWritten() &&
patternEntry.getInitAsWritten()->getSourceRange().isValid()) {
initChild = new (ctx) ASTScope(ASTScopeKind::PatternInitializer, this,
patternBinding.decl, patternBinding.entry);
addChild(new (ctx) ASTScope(ASTScopeKind::PatternInitializer, this,
patternBinding.decl, patternBinding.entry));
}
// Create children for the accessors of any variables in the pattern that
// have them.
patternEntry.getPattern()->forEachVariable([&](VarDecl *var) {
if (hasAccessors(var)) {
// If there is an initializer child that precedes this node (the
// normal case), add teh initializer child first.
if (initChild &&
ctx.SourceMgr.isBeforeInBuffer(
patternEntry.getInitAsWritten()->getEndLoc(),
var->getBracesRange().Start)) {
addChild(initChild);
initChild = nullptr;
}
addChild(new (ctx) ASTScope(this, var));
}
});
// If an initializer child remains, add it now.
if (initChild)
addChild(initChild);
// If there is an active continuation, nest the remaining pattern bindings.
if (getActiveContinuation()) {
// Note: the accessors will follow the pattern binding.
addChild(new (ctx) ASTScope(ASTScopeKind::AfterPatternBinding, this,
patternBinding.decl, patternBinding.entry));
} else {
// Otherwise, add the accessors immediately.
addAccessors(patternEntry.getPattern());
}
break;
}
@@ -413,6 +406,12 @@ void ASTScope::expand() const {
}
case ASTScopeKind::AfterPatternBinding: {
const auto &patternEntry =
patternBinding.decl->getPatternList()[patternBinding.entry];
// Add accessors for the variables in this pattern.
addAccessors(patternEntry.getPattern());
// Create a child for the next pattern binding.
if (auto child = createIfNeeded(this, patternBinding.decl))
addChild(child);
@@ -1504,10 +1503,6 @@ SourceRange ASTScope::getSourceRangeImpl() const {
const auto &patternEntry =
patternBinding.decl->getPatternList()[patternBinding.entry];
// We expect a continuation here.
assert(!patternBinding.decl->getDeclContext()->isLocalContext() ||
getHistoricalContinuation());
return patternEntry.getSourceRange();
}
@@ -1522,11 +1517,8 @@ SourceRange ASTScope::getSourceRangeImpl() const {
const auto &patternEntry =
patternBinding.decl->getPatternList()[patternBinding.entry];
// We expect a continuation here.
assert(getHistoricalContinuation());
// The scope of the binding begins at the end of the binding.
return SourceRange(patternEntry.getSourceRange().End);
return SourceRange(patternEntry.getSourceRange(/*omitAccessors*/true).End,
patternEntry.getSourceRange().End);
}
case ASTScopeKind::BraceStmt:
@@ -1546,8 +1538,6 @@ SourceRange ASTScope::getSourceRangeImpl() const {
// For a guard continuation, the scope extends from the end of the 'else'
// to the end of the continuation.
if (conditionalClause.isGuardContinuation) {
// We expect a continuation here.
assert(getHistoricalContinuation());
const ASTScope *guard = this;
do {
guard = guard->getParent();

View File

@@ -918,26 +918,20 @@ VarDecl *PatternBindingEntry::getAnchoringVarDecl() const {
return variables[0];
}
SourceRange PatternBindingEntry::getSourceRange() const {
ASTContext *ctx = nullptr;
SourceRange PatternBindingEntry::getSourceRange(bool omitAccessors) const {
// Patterns end at the initializer, if present.
SourceLoc endLoc = getOrigInitRange().End;
SourceLoc endLoc;
getPattern()->forEachVariable([&](VarDecl *var) {
auto accessorsEndLoc = var->getBracesRange().End;
if (accessorsEndLoc.isValid()) {
endLoc = accessorsEndLoc;
if (!ctx) ctx = &var->getASTContext();
}
});
// If we're not banned from handling accessors, they follow the initializer.
if (!omitAccessors) {
getPattern()->forEachVariable([&](VarDecl *var) {
auto accessorsEndLoc = var->getBracesRange().End;
if (accessorsEndLoc.isValid())
endLoc = accessorsEndLoc;
});
}
// Check the initializer.
SourceLoc initEndLoc = getOrigInitRange().End;
if (initEndLoc.isValid() &&
(endLoc.isInvalid() ||
(ctx && ctx->SourceMgr.isBeforeInBuffer(endLoc, initEndLoc))))
endLoc = initEndLoc;
// Check the pattern.
// If we didn't find an end yet, check the pattern.
if (endLoc.isInvalid())
endLoc = getPattern()->getEndLoc();

View File

@@ -317,7 +317,7 @@ void swift::convertStoredVarInProtocolToComputed(VarDecl *VD, TypeChecker &TC) {
auto *Get = createGetterPrototype(VD, TC);
// Okay, we have both the getter and setter. Set them in VD.
VD->makeComputed(VD->getLoc(), Get, nullptr, nullptr, VD->getLoc());
VD->makeComputed(SourceLoc(), Get, nullptr, nullptr, SourceLoc());
// We've added some members to our containing class, add them to the members
// list.
@@ -983,7 +983,7 @@ static void convertNSManagedStoredVarToComputed(VarDecl *VD, TypeChecker &TC) {
if (VD->hasAccessorFunctions()) return;
// Okay, we have both the getter and setter. Set them in VD.
VD->makeComputed(VD->getLoc(), Get, Set, nullptr, VD->getLoc());
VD->makeComputed(SourceLoc(), Get, Set, nullptr, SourceLoc());
TC.validateDecl(Get);
TC.validateDecl(Set);
@@ -1736,7 +1736,7 @@ void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) {
setter->setAccessibility(var->getFormalAccess());
}
var->makeComputed(var->getLoc(), getter, setter, nullptr, var->getLoc());
var->makeComputed(SourceLoc(), getter, setter, nullptr, SourceLoc());
// Save the conformance and 'value' decl for later type checking.
behavior->Conformance = conformance;
@@ -1841,8 +1841,7 @@ void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) {
ParamDecl *newValueParam = nullptr;
auto *setter = createSetterPrototype(var, newValueParam, TC);
var->makeComputed(var->getLoc(), getter, setter, nullptr,
var->getLoc());
var->makeComputed(SourceLoc(), getter, setter, nullptr, SourceLoc());
var->setIsBeingTypeChecked(false);
TC.validateDecl(getter);

View File

@@ -366,13 +366,14 @@ class LazyProperties {
// CHECK-EXPANDED: {{^}} `-AbstractFunctionParams {{.*}} funcWithComputedProperties(i:) param 0:0 [142:36 - 155:1] expanded
// CHECK-EXPANDED: {{^}} `-BraceStmt {{.*}} [142:41 - 155:1] expanded
// CHECK-EXPANDED: {{^}} |-Accessors {{.*}} scope_map.(file).func decl.computed@{{.*}}scope_map.swift:143:7 [143:21 - 149:3] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-PatternBinding {{.*}} entry 0 [143:7 - 155:1] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-AfterPatternBinding {{.*}} entry 0 [143:17 - 155:1] expanded
// CHECK-EXPANDED-NEXT: {{^}} |-Accessors {{.*}} scope_map.(file).func decl.computed@{{.*}}scope_map.swift:143:7 [143:21 - 149:3] expanded
// CHECK-EXPANDED-NEXT: {{^}} |-AbstractFunctionDecl {{.*}} _ [144:5 - 145:5] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-AbstractFunctionParams {{.*}} _ param 0:0 [144:5 - 145:5] expanded
// CHECK-EXPANDED: {{^}} `-BraceStmt {{.*}} [144:9 - 145:5] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-AbstractFunctionDecl {{.*}} _ [146:5 - 148:5] expanded
// CHECK-EXPANDED: {{^}} `-BraceStmt {{.*}} [146:9 - 148:5] expanded
// CHECK-EXPANDED: {{^}} `-AfterPatternBinding {{.*}} entry 0 [149:3 - 155:1] expanded
// CHECK-EXPANDED: {{^}} `-AfterPatternBinding {{.*}} entry 1 [149:36 - 155:1] expanded
// CHECK-EXPANDED: {{^}} `-AfterPatternBinding {{.*}} entry 2 [150:21 - 155:1] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-AbstractFunctionDecl {{.*}} _ [150:25 - 155:1] expanded
@@ -493,6 +494,5 @@ class LazyProperties {
// CHECK-SEARCHES: -TypeOrExtensionBody {{.*}} 'LazyProperties' [190:22 - 194:1] expanded
// CHECK-SEARCHES-NEXT: |-PatternBinding {{.*}} entry 0 [191:7 - 191:20] unexpanded
// CHECK-SEARCHES-NEXT: `-PatternBinding {{.*}} entry 0 [193:12 - 193:29] expanded
// CHECK-SEARCHES-NEXT: |-Accessors {{.*}} scope_map.(file).LazyProperties.prop@{{.*}}scope_map.swift:193:12 [193:12 - 193:12] unexpanded
// CHECK-SEARCHES-NEXT: `-PatternInitializer {{.*}} entry 0 [193:24 - 193:29] expanded
// CHECK-SEARCHES-NOT: {{ expanded}}

View File

@@ -78,6 +78,19 @@ extension PConstrained4 where Self : Superclass {
}
}
// Local computed properties.
func localComputedProperties() {
var localProperty: Int {
get {
return localProperty // expected-warning{{attempting to access 'localProperty' within its own getter}}
}
set {
print(localProperty)
}
}
{ print(localProperty) }()
}
// Top-level code.
func topLevel() { }