Skip to content

Commit 07a69c4

Browse files
committed
[ConstraintSystem] Make variadics work with anonymous closure parameters
Since opening closure body is now delayed until contextual type becomes available it's possible to infer anonymous parameters as being variadic based on context and propagate that information down to the closure body. Resolves: rdar://problem/41416758
1 parent 7934cdf commit 07a69c4

File tree

3 files changed

+38
-22
lines changed

3 files changed

+38
-22
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,6 +2853,10 @@ class AnyFunctionType : public TypeBase {
28532853
Param getWithoutLabel() const { return Param(Ty, Identifier(), Flags); }
28542854

28552855
Param withType(Type newType) const { return Param(newType, Label, Flags); }
2856+
2857+
Param withFlags(ParameterTypeFlags flags) const {
2858+
return Param(Ty, Label, flags);
2859+
}
28562860
};
28572861

28582862
class CanParam : public Param {

lib/Sema/CSSimplify.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6596,14 +6596,29 @@ static Type getFunctionBuilderTypeFor(ConstraintSystem &cs, unsigned paramIdx,
65966596
bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
65976597
Type contextualType,
65986598
ConstraintLocatorBuilder locator) {
6599+
auto getContextualParamAt =
6600+
[&contextualType](unsigned index) -> Optional<AnyFunctionType::Param> {
6601+
auto *fnType = contextualType->getAs<FunctionType>();
6602+
return fnType && fnType->getNumParams() > index
6603+
? fnType->getParams()[index]
6604+
: Optional<AnyFunctionType::Param>();
6605+
};
6606+
65996607
auto *closureLocator = typeVar->getImpl().getLocator();
66006608
auto *closure = cast<ClosureExpr>(closureLocator->getAnchor());
6601-
6602-
auto *closureType = getClosureType(closure);
6609+
auto *inferredClosureType = getClosureType(closure);
66036610

66046611
auto *paramList = closure->getParameters();
6612+
SmallVector<AnyFunctionType::Param, 4> parameters;
66056613
for (unsigned i = 0, n = paramList->size(); i != n; ++i) {
6606-
const auto &param = closureType->getParams()[i];
6614+
auto param = inferredClosureType->getParams()[i];
6615+
6616+
// In case of anonymous parameters let's infer flags from context
6617+
// that helps to infer variadic and inout earlier.
6618+
if (closure->hasAnonymousClosureVars()) {
6619+
if (auto contextualParam = getContextualParamAt(i))
6620+
param = param.withFlags(contextualParam->getParameterFlags());
6621+
}
66076622

66086623
Type internalType;
66096624

@@ -6617,17 +6632,25 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
66176632
auto *paramLoc =
66186633
getConstraintLocator(closure, LocatorPathElt::TupleElement(i));
66196634

6620-
internalType = createTypeVariable(paramLoc, TVO_CanBindToLValue |
6621-
TVO_CanBindToNoEscape);
6635+
auto *typeVar = createTypeVariable(paramLoc, TVO_CanBindToLValue |
6636+
TVO_CanBindToNoEscape);
6637+
6638+
// If external parameter is variadic it translates into an array in
6639+
// the body of the closure.
6640+
internalType =
6641+
param.isVariadic() ? ArraySliceType::get(typeVar) : Type(typeVar);
66226642

66236643
auto externalType = param.getOldType();
6624-
addConstraint(ConstraintKind::BindParam, externalType, internalType,
6625-
paramLoc);
6644+
addConstraint(ConstraintKind::BindParam, externalType, typeVar, paramLoc);
66266645
}
66276646

66286647
setType(paramList->get(i), internalType);
6648+
parameters.push_back(param);
66296649
}
66306650

6651+
auto closureType =
6652+
FunctionType::get(parameters, inferredClosureType->getResult(),
6653+
inferredClosureType->getExtInfo());
66316654
assignFixedType(typeVar, closureType, closureLocator);
66326655

66336656
if (auto last = locator.last()) {

test/expr/closure/anonymous.swift

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,27 @@ func takesIntArray(_: [Int]) { }
1313
func takesVariadicInt(_: (Int...) -> ()) { }
1414
func takesVariadicIntInt(_: (Int, Int...) -> ()) { }
1515

16-
func takesVariadicGeneric<T>(_ f: (T...) -> ()) { }
16+
func takesVariadicGeneric<T>(_ f: (T...) -> ()) { } // expected-note {{in call to function 'takesVariadicGeneric'}}
1717

1818
func variadic() {
1919
// These work
2020

21-
// FIXME: Not anymore: rdar://41416758
2221
takesVariadicInt({let _ = $0})
23-
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '(Int...) -> ()'}}
2422
takesVariadicInt({let _: [Int] = $0})
25-
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '(Int...) -> ()'}}
2623

2724
let _: (Int...) -> () = {let _: [Int] = $0}
28-
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to specified type '(Int...) -> ()'}}
2925

3026
takesVariadicInt({takesIntArray($0)})
31-
// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}}
3227

3328
let _: (Int...) -> () = {takesIntArray($0)}
34-
// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}}
3529

3630
takesVariadicGeneric({takesIntArray($0)})
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.
4131

32+
// FIXME: Problem here is related to multi-statement closure body not being type-checked together with
33+
// enclosing context. We could have inferred `$0` to be `[Int]` if `let` was a part of constraint system.
4234
takesVariadicGeneric({let _: [Int] = $0})
43-
// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '(_...) -> ()'}}
35+
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
4436

4537
takesVariadicIntInt({_ = $0; takesIntArray($1)})
46-
// expected-error@-1 {{cannot convert value of type '(_, _) -> ()' to expected argument type '(Int, Int...) -> ()'}}
47-
4838
takesVariadicIntInt({_ = $0; let _: [Int] = $1})
49-
// expected-error@-1 {{cannot convert value of type '(_, _) -> ()' to expected argument type '(Int, Int...) -> ()'}}
5039
}

0 commit comments

Comments
 (0)