Skip to content

Commit 6bbc101

Browse files
committed
[Diagnostics] Correctly diagnose situations when immutable value is passed to inout parameter
Currently the note is going to point to the "callee" but that is incorrect when the failure is related to an argument of a call. Detect this situation in `RValueTreatedAsLValueFailure::diagnoseAsNote` and produce a correct note. Resolves: rdar://150689994
1 parent 622475b commit 6bbc101

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5177,6 +5177,9 @@ ERROR(assignment_bang_has_immutable_subcomponent,none,
51775177
NOTE(candidate_is_not_assignable,none,
51785178
"candidate is not assignable: %kind0",
51795179
(const ValueDecl *))
5180+
NOTE(candidate_expects_inout_argument,none,
5181+
"candidate expects in-out value for parameter #%0 but argument is immutable",
5182+
(unsigned))
51805183

51815184
NOTE(change_to_mutating,none,
51825185
"mark %select{method|%1}0 'mutating' to make 'self' mutable",

lib/Sema/CSDiagnostics.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2049,11 +2049,24 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
20492049
}
20502050

20512051
bool RValueTreatedAsLValueFailure::diagnoseAsNote() {
2052-
auto overload = getCalleeOverloadChoiceIfAvailable(getLocator());
2052+
auto *locator = getLocator();
2053+
2054+
auto overload = getCalleeOverloadChoiceIfAvailable(locator);
20532055
if (!(overload && overload->choice.isDecl()))
20542056
return false;
20552057

20562058
auto *decl = overload->choice.getDecl();
2059+
2060+
if (locator->isLastElement<LocatorPathElt::ArgumentAttribute>()) {
2061+
auto argConv = locator->findLast<LocatorPathElt::ApplyArgToParam>();
2062+
if (!argConv)
2063+
return false;
2064+
2065+
emitDiagnosticAt(decl, diag::candidate_expects_inout_argument,
2066+
argConv->getParamIdx() + 1);
2067+
return true;
2068+
}
2069+
20572070
emitDiagnosticAt(decl, diag::candidate_is_not_assignable, decl);
20582071
return true;
20592072
}

test/Constraints/overload.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,31 @@ do {
349349
}
350350
}
351351
}
352+
353+
do {
354+
struct S {
355+
let x: Int
356+
var y: Int
357+
}
358+
359+
func overloaded(_: String) {}
360+
// expected-note@-1 3 {{candidate expects value of type 'String' for parameter #1 (got 'Int')}}
361+
func overloaded(_: inout Int) {}
362+
// expected-note@-1 3 {{candidate expects in-out value for parameter #1 but argument is immutable}}
363+
364+
func testImmutable(s: S) {
365+
overloaded(s.x) // expected-error {{no exact matches in call to local function 'overloaded'}}
366+
}
367+
368+
func testMutable(s: inout S) {
369+
overloaded(s.x) // expected-error {{no exact matches in call to local function 'overloaded'}}
370+
}
371+
372+
func testImmutableBase(s: S) {
373+
overloaded(s.y) // expected-error {{no exact matches in call to local function 'overloaded'}}
374+
}
375+
376+
func testMissingAddressOf(s: inout S) {
377+
overloaded(s.y) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
378+
}
379+
}

0 commit comments

Comments
 (0)