Skip to content

Commit f1ea135

Browse files
committed
fix <rdar://problem/27384685> QoI: Poor diagnostic when assigning a value to a method
We previously said: x.method = 1 // error: cannot assign to property: 'x' is immutable we now say: error: cannot assign to property: 'method' is a method
1 parent 979ff4e commit f1ea135

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -538,12 +538,17 @@ resolveImmutableBase(Expr *expr, ConstraintSystem &CS) {
538538
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
539539
// If we found a decl for the UDE, check it.
540540
auto loc = CS.getConstraintLocator(UDE, ConstraintLocator::Member);
541-
auto *member = dyn_cast_or_null<VarDecl>(findResolvedMemberRef(loc, CS));
542-
543-
// If the member isn't settable, then it is the problem: return it.
544-
if (member) {
545-
if (!member->isSettable(nullptr) ||
546-
!member->isSetterAccessibleFrom(CS.DC))
541+
542+
// If we can resolve a member, we can determine whether it is settable in
543+
// this context.
544+
if (auto *member = findResolvedMemberRef(loc, CS)) {
545+
auto *memberVD = dyn_cast<VarDecl>(member);
546+
547+
// If the member isn't a vardecl (e.g. its a funcdecl), or it isn't
548+
// settable, then it is the problem: return it.
549+
if (!memberVD ||
550+
!member->isSettable(nullptr) ||
551+
!memberVD->isSetterAccessibleFrom(CS.DC))
547552
return { expr, member };
548553
}
549554

@@ -641,6 +646,22 @@ static void diagnoseSubElementFailure(Expr *destExpr,
641646
.highlight(immInfo.first->getSourceRange());
642647
return;
643648
}
649+
650+
// If we're trying to set an unapplied method, say that.
651+
if (auto *VD = dyn_cast_or_null<ValueDecl>(immInfo.second)) {
652+
std::string message = "'";
653+
message += VD->getName().str().str();
654+
message += "'";
655+
656+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD))
657+
message += AFD->getImplicitSelfDecl() ? " is a method" : " is a function";
658+
else
659+
message += " is not settable";
660+
661+
TC.diagnose(loc, diagID, message)
662+
.highlight(immInfo.first->getSourceRange());
663+
return;
664+
}
644665

645666
// If the expression is the result of a call, it is an rvalue, not a mutable
646667
// lvalue.

test/ClangModules/objc_parse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func properties(_ b: B) {
119119
// An informal property cannot be made formal in a subclass. The
120120
// formal property is simply ignored.
121121
b.informalMadeFormal()
122-
b.informalMadeFormal = i // expected-error{{cannot assign to property: 'b' is a 'let' constant}}
122+
b.informalMadeFormal = i // expected-error{{cannot assign to property: 'informalMadeFormal' is a method}}
123123
b.setInformalMadeFormal(5)
124124

125125
b.overriddenProp = 17

test/Sema/immutability.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,11 @@ func testConditional(b : Bool) {
563563

564564
(b ? x : z.t).mutatingfunc() // expected-error {{cannot use mutating member on immutable value: result of conditional operator '? :' is never mutable}}
565565
}
566+
567+
568+
569+
// <rdar://problem/27384685> QoI: Poor diagnostic when assigning a value to a method
570+
func f(a : FooClass, b : LetStructMembers) {
571+
a.baz = 1 // expected-error {{cannot assign to property: 'baz' is a method}}
572+
b.f = 42 // expected-error {{cannot assign to property: 'f' is a method}}
573+
}

0 commit comments

Comments
 (0)