Skip to content

Commit 9c3f2aa

Browse files
Merge pull request swiftlang#68301 from LucianoPAlmeida/coerce-function
2 parents 85016b5 + 50130b0 commit 9c3f2aa

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,6 +2761,17 @@ bool ContextualFailure::diagnoseAsNote() {
27612761
}
27622762
}
27632763

2764+
// Note that mentions candidate type number of parameters diff.
2765+
auto fromFnType = getFromType()->getAs<FunctionType>();
2766+
auto toFnType = getToType()->getAs<FunctionType>();
2767+
if (fromFnType && toFnType &&
2768+
fromFnType->getNumParams() > toFnType->getNumParams()) {
2769+
emitDiagnosticAt(decl, diag::candidate_with_extraneous_args, fromFnType,
2770+
fromFnType->getNumParams(), toFnType,
2771+
toFnType->getNumParams());
2772+
return true;
2773+
}
2774+
27642775
emitDiagnosticAt(decl, diag::found_candidate_type, getFromType());
27652776
return true;
27662777
}

lib/Sema/CSSimplify.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,18 +3425,36 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
34253425
if (!anchor)
34263426
return getTypeMatchFailure(argumentLocator);
34273427

3428-
// If there are missing arguments, let's add them
3429-
// using parameter as a template.
3430-
if (diff < 0) {
3431-
if (fixMissingArguments(*this, anchor, func1Params, func2Params,
3432-
abs(diff), loc))
3428+
// The param diff is in a function type coercion context
3429+
//
3430+
// func fn(_: Int) {}
3431+
// let i: Int = 0
3432+
// (fn as (Int, Int) -> Void)(i, i)
3433+
//
3434+
// Since we are not in a function argument application, simply record
3435+
// a function type mismatch instead of an argument fix.
3436+
// Except for when a closure is a subexpr because closure expr parameters
3437+
// syntax can be added or removed by missing/extraneous arguments fix.
3438+
if (loc->isForCoercion() && !isExpr<ClosureExpr>(anchor)) {
3439+
auto *fix = ContextualMismatch::create(*this, func1, func2, loc);
3440+
if (recordFix(fix))
34333441
return getTypeMatchFailure(argumentLocator);
34343442
} else {
3435-
// If there are extraneous arguments, let's remove
3436-
// them from the list.
3437-
if (fixExtraneousArguments(*this, func2, func1Params, diff, loc))
3438-
return getTypeMatchFailure(argumentLocator);
3443+
// If there are missing arguments, let's add them
3444+
// using parameter as a template.
3445+
if (diff < 0) {
3446+
if (fixMissingArguments(*this, anchor, func1Params, func2Params,
3447+
abs(diff), loc))
3448+
return getTypeMatchFailure(argumentLocator);
3449+
} else {
3450+
// If there are extraneous arguments, let's remove
3451+
// them from the list.
3452+
if (fixExtraneousArguments(*this, func2, func1Params, diff, loc))
3453+
return getTypeMatchFailure(argumentLocator);
3454+
}
3455+
}
34393456

3457+
if (diff > 0) {
34403458
// Drop all of the extraneous arguments.
34413459
auto numParams = func2Params.size();
34423460
func1Params.erase(func1Params.begin() + numParams, func1Params.end());

test/expr/cast/as_coerce.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,28 @@ let _: Int = any as Int // expected-error {{'Any' is not convertible to 'Int'}}
163163
// expected-note@-1 {{did you mean to use 'as!' to force downcast?}} {{18-20=as!}}
164164
let _: Int? = any as Int // expected-error {{'Any' is not convertible to 'Int'}}
165165
// expected-note@-1 {{did you mean to use 'as?' to conditionally downcast?}} {{19-21=as?}}
166+
167+
// https://github.com/apple/swift/issues/63926
168+
169+
do {
170+
func fn(_: Int) {} // expected-note {{found candidate with type '(Int) -> ()'}}
171+
// expected-note@-1 {{candidate '(Int) -> ()' has 1 parameter, but context '() -> Void' has 0}}
172+
func fn(_: Bool) {} // expected-note {{found candidate with type '(Bool) -> ()'}}
173+
// expected-note@-1 {{candidate '(Bool) -> ()' has 1 parameter, but context '() -> Void' has 0}}
174+
175+
func fn_1(_: Bool) {}
176+
177+
let i = 0
178+
// Missing parameters.
179+
(fn as (Int, Int) -> Void)(i, i) // expected-error {{cannot convert value of type '(Int) -> ()' to type '(Int, Int) -> Void' in coercion}}
180+
(fn as (Bool, Bool) -> Void)(i, i) // expected-error {{cannot convert value of type '(Bool) -> ()' to type '(Bool, Bool) -> Void' in coercion}}
181+
// expected-error@-1 2{{type 'Int' cannot be used as a boolean; test for '!= 0' instead}}
182+
(fn as (Int, Bool) -> Void)(i, i) // expected-error {{cannot convert value of type '(Int) -> ()' to type '(Int, Bool) -> Void' in coercion}}
183+
// expected-error@-1 {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}}
184+
(fn as (String) -> Void)(i) // expected-error {{no exact matches in reference to local function 'fn'}}
185+
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}}
186+
187+
// Extraneous parameters.
188+
(fn as () -> Void)() // expected-error {{no exact matches in reference to local function 'fn'}}
189+
(fn_1 as () -> Void)() // expected-error {{cannot convert value of type '(Bool) -> ()' to type '() -> Void' in coercion}}
190+
}

0 commit comments

Comments
 (0)