diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 02889d855de7f..84b40e6d30321 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -5136,6 +5136,9 @@ ERROR(assignment_bang_has_immutable_subcomponent,none, NOTE(candidate_is_not_assignable,none, "candidate is not assignable: %kind0", (const ValueDecl *)) +NOTE(candidate_expects_inout_argument,none, + "candidate expects in-out value for parameter #%0 but argument is immutable", + (unsigned)) NOTE(change_to_mutating,none, "mark %select{method|%1}0 'mutating' to make 'self' mutable", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index a8532d2be374a..4c88ddca416c6 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2049,11 +2049,24 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } bool RValueTreatedAsLValueFailure::diagnoseAsNote() { - auto overload = getCalleeOverloadChoiceIfAvailable(getLocator()); + auto *locator = getLocator(); + + auto overload = getCalleeOverloadChoiceIfAvailable(locator); if (!(overload && overload->choice.isDecl())) return false; auto *decl = overload->choice.getDecl(); + + if (locator->isLastElement()) { + auto argConv = locator->findLast(); + if (!argConv) + return false; + + emitDiagnosticAt(decl, diag::candidate_expects_inout_argument, + argConv->getParamIdx() + 1); + return true; + } + emitDiagnosticAt(decl, diag::candidate_is_not_assignable, decl); return true; } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 4b7195a87dc73..a25c415733d20 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -730,7 +730,9 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( } if (locator->isLastElement()) { - return getConstraintLocator(anchor, path.drop_back()); + auto argLoc = getConstraintLocator(anchor, path.drop_back()); + return getCalleeLocator(argLoc, lookThroughApply, getType, simplifyType, + getOverloadFor); } // If we have a locator that starts with a key path component element, we diff --git a/test/Constraints/overload.swift b/test/Constraints/overload.swift index 59f918dddc257..87c132e21c5ac 100644 --- a/test/Constraints/overload.swift +++ b/test/Constraints/overload.swift @@ -349,3 +349,31 @@ do { } } } + +do { + struct S { + let x: Int + var y: Int + } + + func overloaded(_: String) {} + // expected-note@-1 3 {{candidate expects value of type 'String' for parameter #1 (got 'Int')}} + func overloaded(_: inout Int) {} + // expected-note@-1 3 {{candidate expects in-out value for parameter #1 but argument is immutable}} + + func testImmutable(s: S) { + overloaded(s.x) // expected-error {{no exact matches in call to local function 'overloaded'}} + } + + func testMutable(s: inout S) { + overloaded(s.x) // expected-error {{no exact matches in call to local function 'overloaded'}} + } + + func testImmutableBase(s: S) { + overloaded(s.y) // expected-error {{no exact matches in call to local function 'overloaded'}} + } + + func testMissingAddressOf(s: inout S) { + overloaded(s.y) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}} + } +}