mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user