Skip to content

Commit 15c58d1

Browse files
committed
[ConstraintSystem] Detect passing array to variadic argument in function conversions
Initially this problem was only detected and diagnosed for calls. So let's extend it to function conversions as well e.g.: ```swift func foo<T>(_: [T]) {} func bar<T>(_ f: (T...) -> ()) {} bar { foo($0) } ```
1 parent 34f5b52 commit 15c58d1

File tree

3 files changed

+52
-25
lines changed

3 files changed

+52
-25
lines changed

lib/Sema/CSFix.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -929,25 +929,29 @@ static bool isValueOfRawRepresentable(ConstraintSystem &cs,
929929
ExpandArrayIntoVarargs *
930930
ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType,
931931
Type paramType,
932-
ConstraintLocatorBuilder locator) {
933-
auto constraintLocator = cs.getConstraintLocator(locator);
932+
ConstraintLocatorBuilder builder) {
933+
auto *locator = cs.getConstraintLocator(builder);
934+
935+
auto argLoc = locator->getLastElementAs<LocatorPathElt::ApplyArgToParam>();
936+
if (!(argLoc && argLoc->getParameterFlags().isVariadic()))
937+
return nullptr;
938+
934939
auto elementType = cs.isArrayType(argType);
935-
if (elementType &&
936-
constraintLocator->getLastElementAs<LocatorPathElt::ApplyArgToParam>()
937-
->getParameterFlags()
938-
.isVariadic()) {
939-
auto options = ConstraintSystem::TypeMatchOptions(
940-
ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix |
941-
ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints);
942-
auto result =
943-
cs.matchTypes(*elementType, paramType,
944-
ConstraintKind::ArgumentConversion, options, locator);
945-
if (result.isSuccess())
946-
return new (cs.getAllocator())
947-
ExpandArrayIntoVarargs(cs, argType, paramType, constraintLocator);
948-
}
940+
if (!elementType)
941+
return nullptr;
949942

950-
return nullptr;
943+
ConstraintSystem::TypeMatchOptions options;
944+
options |= ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix;
945+
options |= ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints;
946+
947+
auto result = cs.matchTypes(*elementType, paramType, ConstraintKind::Subtype,
948+
options, builder);
949+
950+
if (result.isFailure())
951+
return nullptr;
952+
953+
return new (cs.getAllocator())
954+
ExpandArrayIntoVarargs(cs, argType, paramType, locator);
951955
}
952956

953957
bool ExpandArrayIntoVarargs::diagnose(bool asNote) const {

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,8 +1767,31 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
17671767
auto func2Param = func2Params[i];
17681768

17691769
// Variadic bit must match.
1770-
if (func1Param.isVariadic() != func2Param.isVariadic())
1771-
return getTypeMatchFailure(argumentLocator);
1770+
if (func1Param.isVariadic() != func2Param.isVariadic()) {
1771+
if (!(shouldAttemptFixes() && func2Param.isVariadic()))
1772+
return getTypeMatchFailure(argumentLocator);
1773+
1774+
auto argType =
1775+
getFixedTypeRecursive(func1Param.getPlainType(), /*wantRValue=*/true);
1776+
auto varargsType = func2Param.getPlainType();
1777+
1778+
// Delay solving this constriant until argument is resolved.
1779+
if (argType->is<TypeVariableType>()) {
1780+
addUnsolvedConstraint(Constraint::create(
1781+
*this, kind, func1, func2, getConstraintLocator(locator)));
1782+
return getTypeMatchSuccess();
1783+
}
1784+
1785+
auto *fix = ExpandArrayIntoVarargs::attempt(
1786+
*this, argType, varargsType,
1787+
argumentLocator.withPathElement(LocatorPathElt::ApplyArgToParam(
1788+
i, i, func2Param.getParameterFlags())));
1789+
1790+
if (!fix || recordFix(fix))
1791+
return getTypeMatchFailure(argumentLocator);
1792+
1793+
continue;
1794+
}
17721795

17731796
// Labels must match.
17741797
//

test/expr/closure/anonymous.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ func variadic() {
2727
let _: (Int...) -> () = {let _: [Int] = $0}
2828
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to specified type '(Int...) -> ()'}}
2929

30-
// FIXME: Make the rest work
3130
takesVariadicInt({takesIntArray($0)})
32-
// expected-error@-1 {{cannot convert value of type '([Int]) -> ()' to expected argument type '(Int...) -> ()'}}
31+
// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}}
3332

3433
let _: (Int...) -> () = {takesIntArray($0)}
35-
// expected-error@-1 {{cannot convert value of type '([Int]) -> ()' to specified type '(Int...) -> ()'}}
34+
// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}}
3635

37-
// TODO(diagnostics): This requires special handling - variadic vs. array
3836
takesVariadicGeneric({takesIntArray($0)})
39-
// expected-error@-1 {{cannot convert value of type 'Array<_>' to expected argument type '[Int]'}}
40-
// expected-note@-2 {{arguments to generic parameter 'Element' ('_' and 'Int') are expected to be equal}}
37+
// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}}
38+
39+
// FIXME(diagnostics): Problems here are related to multi-statement closure bodies not being type-checked together with
40+
// enclosing context.
4141

4242
takesVariadicGeneric({let _: [Int] = $0})
4343
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '(_...) -> ()'}}

0 commit comments

Comments
 (0)