Skip to content

Commit 6b9b764

Browse files
authored
Merge pull request swiftlang#27614 from xedin/inout-type-mismatch
[ConstraintSystem] Detect and diagnose type mismatch failures of `ino…
2 parents 748b646 + 8e16aa4 commit 6b9b764

File tree

7 files changed

+54
-20
lines changed

7 files changed

+54
-20
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,8 @@ ERROR(cannot_convert_argument_value,none,
381381
(Type,Type))
382382

383383
NOTE(candidate_has_invalid_argument_at_position,none,
384-
"candidate expects value of type %0 for parameter #%1",
385-
(Type, unsigned))
384+
"candidate expects %select{|in-out }2value of type %0 for parameter #%1",
385+
(Type, unsigned, bool))
386386

387387
ERROR(cannot_convert_array_to_variadic,none,
388388
"cannot pass array of type %0 as variadic arguments of type %1",

lib/Sema/CSDiagnostics.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,12 @@ bool ContextualFailure::diagnoseConversionToNil() const {
21422142
}
21432143

21442144
void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
2145+
auto *locator = getLocator();
2146+
// Can't apply any of the fix-its below if this failure
2147+
// is related to `inout` argument.
2148+
if (locator->isLastElement<LocatorPathElt::LValueConversion>())
2149+
return;
2150+
21452151
if (trySequenceSubsequenceFixIts(diagnostic))
21462152
return;
21472153

@@ -5078,9 +5084,11 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
50785084
}
50795085

50805086
bool ArgumentMismatchFailure::diagnoseAsNote() {
5087+
auto *locator = getLocator();
50815088
if (auto *callee = getCallee()) {
50825089
emitDiagnostic(callee, diag::candidate_has_invalid_argument_at_position,
5083-
getToType(), getParamPosition());
5090+
getToType(), getParamPosition(),
5091+
locator->isLastElement<LocatorPathElt::LValueConversion>());
50845092
return true;
50855093
}
50865094

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2654,11 +2654,23 @@ bool ConstraintSystem::repairFailures(
26542654
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
26552655
TMF_ApplyingFix, locator);
26562656

2657-
if (!result.isFailure()) {
2658-
conversionsOrFixes.push_back(
2659-
AllowInOutConversion::create(*this, lhs, rhs, loc));
2660-
break;
2657+
ConstraintFix *fix = nullptr;
2658+
if (result.isFailure()) {
2659+
// If this is a "destination" argument to a mutating operator
2660+
// like `+=`, let's consider it contextual and only attempt
2661+
// to fix type mismatch on the "source" right-hand side of
2662+
// such operators.
2663+
if (isOperatorArgument(loc) &&
2664+
loc->findLast<LocatorPathElt::ApplyArgToParam>()->getArgIdx() == 0)
2665+
break;
2666+
2667+
fix = AllowArgumentMismatch::create(*this, lhs, rhs, loc);
2668+
} else {
2669+
fix = AllowInOutConversion::create(*this, lhs, rhs, loc);
26612670
}
2671+
2672+
conversionsOrFixes.push_back(fix);
2673+
break;
26622674
}
26632675

26642676
if (elt.getKind() != ConstraintLocator::ApplyArgToParam)

lib/Sema/ConstraintSystem.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,6 +3203,21 @@ bool constraints::isPatternMatchingOperator(Expr *expr) {
32033203
return isOperator(expr, "~=");
32043204
}
32053205

3206+
bool constraints::isOperatorArgument(ConstraintLocator *locator,
3207+
StringRef expectedOperator) {
3208+
if (!locator->findLast<LocatorPathElt::ApplyArgToParam>())
3209+
return false;
3210+
3211+
if (auto *AE = dyn_cast_or_null<ApplyExpr>(locator->getAnchor())) {
3212+
if (isa<PrefixUnaryExpr>(AE) || isa<BinaryExpr>(AE) ||
3213+
isa<PostfixUnaryExpr>(AE))
3214+
return expectedOperator.empty() ||
3215+
isOperator(AE->getFn(), expectedOperator);
3216+
}
3217+
3218+
return false;
3219+
}
3220+
32063221
bool constraints::isArgumentOfPatternMatchingOperator(
32073222
ConstraintLocator *locator) {
32083223
auto *binaryOp = dyn_cast_or_null<BinaryExpr>(locator->getAnchor());
@@ -3213,13 +3228,6 @@ bool constraints::isArgumentOfPatternMatchingOperator(
32133228

32143229
bool constraints::isArgumentOfReferenceEqualityOperator(
32153230
ConstraintLocator *locator) {
3216-
if (!locator->findLast<LocatorPathElt::ApplyArgToParam>())
3217-
return false;
3218-
3219-
if (auto *binaryOp = dyn_cast_or_null<BinaryExpr>(locator->getAnchor())) {
3220-
auto *fnExpr = binaryOp->getFn();
3221-
return isOperator(fnExpr, "===") || isOperator(fnExpr, "!==");
3222-
}
3223-
3224-
return false;
3231+
return isOperatorArgument(locator, "===") ||
3232+
isOperatorArgument(locator, "!==");
32253233
}

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3987,6 +3987,12 @@ Expr *simplifyLocatorToAnchor(ConstraintLocator *locator);
39873987
/// wasn't of one of the kinds listed above.
39883988
Expr *getArgumentExpr(Expr *expr, unsigned index);
39893989

3990+
/// Determine whether given locator points to one of the arguments
3991+
/// associated with the call to an operator. If the operator name
3992+
/// is empty `true` is returned for any kind of operator.
3993+
bool isOperatorArgument(ConstraintLocator *locator,
3994+
StringRef expectedOperator = "");
3995+
39903996
/// Determine whether given locator points to one of the arguments
39913997
/// associated with implicit `~=` (pattern-matching) operator
39923998
bool isArgumentOfPatternMatchingOperator(ConstraintLocator *locator);

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ let _: Color = .frob(1, i) // expected-error {{missing argument label 'b:' in c
522522
// expected-error@-1 {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
523523
let _: Color = .frob(1, b: i) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}} {{28-28=&}}
524524
let _: Color = .frob(1, &d) // expected-error {{missing argument label 'b:' in call}}
525+
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}}
525526
let _: Color = .frob(1, b: &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
526527
var someColor : Color = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}
527528
someColor = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}

test/expr/postfix/dot/init_ref_delegation.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -549,10 +549,9 @@ struct MultipleMemberAccesses {
549549

550550
func sr10670() {
551551
struct S {
552-
init(_ x: inout String) {}
553-
init(_ x: inout [Int]) {}
552+
init(_ x: inout String) {} // expected-note {{candidate expects in-out value of type 'String' for parameter #1}}
553+
init(_ x: inout [Int]) {} // expected-note {{candidate expects in-out value of type '[Int]' for parameter #1}}
554554
}
555555
var a = 0
556-
S.init(&a) // expected-error {{cannot invoke 'S.Type.init' with an argument list of type '(inout Int)'}}
557-
// expected-note@-1 {{overloads for 'S.Type.init' exist with these partially matching parameter lists: (inout String), (inout [Int])}}
556+
S.init(&a) // expected-error {{no exact matches in call to initializer}}
558557
}

0 commit comments

Comments
 (0)