Skip to content

Commit 24625bb

Browse files
committed
[ConstraintSystem] Fix support for a single pack expansion parameter in init references
In Swift 5 and earlier initializer references are handled in a special way that uses a type variable to represent a type of the parameter list. Such type variables should be allowed to bind to a pack expansion type to support cases where initializer has a single unlabeled variadic generic parameter - `init(_ data: repeat each T)`.
1 parent a2d2fef commit 24625bb

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1699,7 +1699,8 @@ namespace {
16991699
if (!CS.getASTContext().isSwiftVersionAtLeast(6)) {
17001700
auto paramTypeVar = CS.createTypeVariable(
17011701
CS.getConstraintLocator(expr, ConstraintLocator::ApplyArgument),
1702-
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
1702+
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape |
1703+
TVO_CanBindToPack);
17031704
CS.addConstraint(ConstraintKind::BindTupleOfFunctionParams, methodTy,
17041705
paramTypeVar, CS.getConstraintLocator(expr));
17051706
}

lib/Sema/CSSimplify.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4311,21 +4311,37 @@ ConstraintSystem::matchTypesBindTypeVar(
43114311
return getTypeMatchFailure(locator);
43124312
}
43134313

4314-
// Binding to a pack expansion type is always an error. This indicates
4315-
// that a pack expansion expression was used in a context that doesn't
4316-
// support it.
4314+
// Binding to a pack expansion type is always an error in Swift 6 mode.
4315+
// This indicates that a pack expansion expression was used in a context
4316+
// that doesn't support it.
4317+
//
4318+
// In Swift 5 and earlier initializer references are handled in a special
4319+
// way that uses a type variable to represent a type of the parameter
4320+
// list. Such type variables should be allowed to bind to a pack expansion
4321+
// type to support cases where initializer has a single unlabeled variadic
4322+
// generic parameter - `init(_ data: repeat each T)`.
4323+
//
4324+
// See BindTupleOfFunctionParams constraint for more details.
43174325
if (type->is<PackExpansionType>()) {
4318-
if (!shouldAttemptFixes())
4319-
return getTypeMatchFailure(locator);
4326+
bool representsParameterList =
4327+
typeVar->getImpl()
4328+
.getLocator()
4329+
->isLastElement<LocatorPathElt::ApplyArgument>();
43204330

4321-
auto *fix =
4322-
AllowInvalidPackExpansion::create(*this, getConstraintLocator(locator));
4323-
if (recordFix(fix))
4324-
return getTypeMatchFailure(locator);
4331+
if (!(typeVar->getImpl().canBindToPack() && representsParameterList) ||
4332+
getASTContext().isSwiftVersionAtLeast(6)) {
4333+
if (!shouldAttemptFixes())
4334+
return getTypeMatchFailure(locator);
43254335

4326-
// Don't allow the pack expansion type to propagate to other
4327-
// bindings.
4328-
type = PlaceholderType::get(typeVar->getASTContext(), typeVar);
4336+
auto *fix = AllowInvalidPackExpansion::create(
4337+
*this, getConstraintLocator(locator));
4338+
if (recordFix(fix))
4339+
return getTypeMatchFailure(locator);
4340+
4341+
// Don't allow the pack expansion type to propagate to other
4342+
// bindings.
4343+
type = PlaceholderType::get(typeVar->getASTContext(), typeVar);
4344+
}
43294345
}
43304346

43314347
// We do not allow keypaths to go through AnyObject. Let's create a fix
@@ -7860,7 +7876,8 @@ ConstraintSystem::simplifyConstructionConstraint(
78607876
if (!getASTContext().isSwiftVersionAtLeast(6)) {
78617877
auto paramTypeVar = createTypeVariable(
78627878
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
7863-
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
7879+
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape |
7880+
TVO_CanBindToPack);
78647881
addConstraint(ConstraintKind::BindTupleOfFunctionParams, memberType,
78657882
paramTypeVar, locator);
78667883
}

test/Constraints/pack-expansion-expressions.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,27 @@ func invalidRepeat<each T>(t: repeat each T) {
262262
// expected-error@-1 {{value pack expansion can only appear inside a function argument list or tuple element}}
263263
}
264264

265+
// Make sure that single parameter initializers are handled correctly because
266+
// the have special type-checking rules in Swift < 6.
267+
func test_init_refs_with_single_pack_expansion_param() {
268+
struct Data<each V> {
269+
init(_: repeat each V) {}
270+
}
271+
272+
_ = Data() // Ok
273+
_ = Data(42) // Ok
274+
_ = Data(42, "") // Ok
275+
276+
struct EmptyAmbiguous<each V> {
277+
init(_: repeat each V) {} // expected-note {{found this candidate}}
278+
init(x: repeat each V) {} // expected-note {{found this candidate}}
279+
}
280+
281+
_ = EmptyAmbiguous() // expected-error {{ambiguous use of 'init'}}
282+
_ = EmptyAmbiguous(x: 42)
283+
_ = EmptyAmbiguous(x: (42, "")) // Ok
284+
}
285+
265286
func test_pack_expansions_with_closures() {
266287
func takesVariadicFunction<each T>(function: (repeat each T) -> Int) {}
267288

0 commit comments

Comments
 (0)