Skip to content

Commit

Permalink
fix <rdar://problem/27384685> QoI: Poor diagnostic when assigning a v…
Browse files Browse the repository at this point in the history
…alue 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
  • Loading branch information
lattner committed Jul 31, 2016
1 parent 979ff4e commit f1ea135
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 7 deletions.
33 changes: 27 additions & 6 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,17 @@ resolveImmutableBase(Expr *expr, ConstraintSystem &CS) {
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
// If we found a decl for the UDE, check it.
auto loc = CS.getConstraintLocator(UDE, ConstraintLocator::Member);
auto *member = dyn_cast_or_null<VarDecl>(findResolvedMemberRef(loc, CS));

// If the member isn't settable, then it is the problem: return it.
if (member) {
if (!member->isSettable(nullptr) ||
!member->isSetterAccessibleFrom(CS.DC))

// If we can resolve a member, we can determine whether it is settable in
// this context.
if (auto *member = findResolvedMemberRef(loc, CS)) {
auto *memberVD = dyn_cast<VarDecl>(member);

// If the member isn't a vardecl (e.g. its a funcdecl), or it isn't
// settable, then it is the problem: return it.
if (!memberVD ||
!member->isSettable(nullptr) ||
!memberVD->isSetterAccessibleFrom(CS.DC))
return { expr, member };
}

Expand Down Expand Up @@ -641,6 +646,22 @@ static void diagnoseSubElementFailure(Expr *destExpr,
.highlight(immInfo.first->getSourceRange());
return;
}

// If we're trying to set an unapplied method, say that.
if (auto *VD = dyn_cast_or_null<ValueDecl>(immInfo.second)) {
std::string message = "'";
message += VD->getName().str().str();
message += "'";

if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD))
message += AFD->getImplicitSelfDecl() ? " is a method" : " is a function";
else
message += " is not settable";

TC.diagnose(loc, diagID, message)
.highlight(immInfo.first->getSourceRange());
return;
}

// If the expression is the result of a call, it is an rvalue, not a mutable
// lvalue.
Expand Down
2 changes: 1 addition & 1 deletion test/ClangModules/objc_parse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func properties(_ b: B) {
// An informal property cannot be made formal in a subclass. The
// formal property is simply ignored.
b.informalMadeFormal()
b.informalMadeFormal = i // expected-error{{cannot assign to property: 'b' is a 'let' constant}}
b.informalMadeFormal = i // expected-error{{cannot assign to property: 'informalMadeFormal' is a method}}
b.setInformalMadeFormal(5)

b.overriddenProp = 17
Expand Down
8 changes: 8 additions & 0 deletions test/Sema/immutability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -563,3 +563,11 @@ func testConditional(b : Bool) {

(b ? x : z.t).mutatingfunc() // expected-error {{cannot use mutating member on immutable value: result of conditional operator '? :' is never mutable}}
}



// <rdar://problem/27384685> QoI: Poor diagnostic when assigning a value to a method
func f(a : FooClass, b : LetStructMembers) {
a.baz = 1 // expected-error {{cannot assign to property: 'baz' is a method}}
b.f = 42 // expected-error {{cannot assign to property: 'f' is a method}}
}

0 comments on commit f1ea135

Please sign in to comment.