Skip to content

Commit 8d208be

Browse files
committed
[CSDiagnostics] Use qualified lookup for 'self.' fix-it
We only want to look for properties on the type which the method is a member of. Resolves SR-11786.
1 parent 5eb1df5 commit 8d208be

File tree

2 files changed

+43
-15
lines changed

2 files changed

+43
-15
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,21 +1619,37 @@ bool AssignmentFailure::diagnoseAsError() {
16191619
// If there is a masked instance variable of the same type, emit a
16201620
// note to fixit prepend a 'self.'.
16211621
if (auto typeContext = DC->getInnermostTypeContext()) {
1622-
UnqualifiedLookup lookup(VD->getFullName(), typeContext);
1623-
for (auto &result : lookup.Results) {
1624-
const VarDecl *typeVar = dyn_cast<VarDecl>(result.getValueDecl());
1625-
if (typeVar && typeVar != VD && typeVar->isSettable(DC) &&
1626-
typeVar->isSetterAccessibleFrom(DC) &&
1627-
typeVar->getType()->isEqual(VD->getType())) {
1628-
// But not in its own accessor.
1629-
auto AD =
1630-
dyn_cast_or_null<AccessorDecl>(DC->getInnermostMethodContext());
1631-
if (!AD || AD->getStorage() != typeVar) {
1632-
emitDiagnostic(Loc, diag::masked_instance_variable,
1633-
typeContext->getSelfTypeInContext())
1634-
.fixItInsert(Loc, "self.");
1635-
}
1636-
}
1622+
SmallVector<ValueDecl *, 2> results;
1623+
DC->lookupQualified(typeContext->getSelfNominalTypeDecl(),
1624+
VD->getFullName(),
1625+
NL_QualifiedDefault | NL_RemoveNonVisible, results);
1626+
1627+
auto foundProperty = llvm::find_if(results, [&](ValueDecl *decl) {
1628+
// We're looking for a settable property that is the same type as the
1629+
// var we found.
1630+
auto *var = dyn_cast<VarDecl>(decl);
1631+
if (!var || var == VD)
1632+
return false;
1633+
1634+
if (!var->isSettable(DC) || !var->isSetterAccessibleFrom(DC))
1635+
return false;
1636+
1637+
if (!var->getType()->isEqual(VD->getType()))
1638+
return false;
1639+
1640+
// Don't suggest a property if we're in one of its accessors.
1641+
auto *methodDC = DC->getInnermostMethodContext();
1642+
if (auto *AD = dyn_cast_or_null<AccessorDecl>(methodDC))
1643+
if (AD->getStorage() == var)
1644+
return false;
1645+
1646+
return true;
1647+
});
1648+
1649+
if (foundProperty != results.end()) {
1650+
emitDiagnostic(Loc, diag::masked_instance_variable,
1651+
typeContext->getSelfTypeInContext())
1652+
.fixItInsert(Loc, "self.");
16371653
}
16381654
}
16391655

test/Sema/immutability.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,15 @@ extension JustAProtocol {
701701
name = "World" // expected-error {{cannot assign to property: 'self' is immutable}}
702702
}
703703
}
704+
705+
struct S {
706+
var x = 0
707+
708+
struct Nested {
709+
func foo() {
710+
// SR-11786: Make sure we don't offer the 'self.' fix-it here.
711+
let x = 0 // expected-note {{change 'let' to 'var' to make it mutable}}
712+
x += 1 // expected-error {{left side of mutating operator isn't mutable: 'x' is a 'let' constant}}
713+
}
714+
}
715+
}

0 commit comments

Comments
 (0)