Skip to content

Commit a5d92bc

Browse files
authored
Merge pull request #82053 from xedin/rdar-150689994
[Diagnostics] Correctly diagnose situations when immutable value is passed to `inout` parameter
2 parents e79c939 + 6bbc101 commit a5d92bc

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
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
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,9 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
730730
}
731731

732732
if (locator->isLastElement<LocatorPathElt::ArgumentAttribute>()) {
733-
return getConstraintLocator(anchor, path.drop_back());
733+
auto argLoc = getConstraintLocator(anchor, path.drop_back());
734+
return getCalleeLocator(argLoc, lookThroughApply, getType, simplifyType,
735+
getOverloadFor);
734736
}
735737

736738
// If we have a locator that starts with a key path component element, we

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)