Skip to content

Commit cc2b6ce

Browse files
committed
[CSSimplify] Type matching should maintain tuples when matching types with pack expansions
Pack expansion flattening could result in lose of tuple structure or introduce a single element tuples (which are effectively parens), to aid in matching `matchTypes` should introduce/maintain tuples on both sides of the comparison until the structure is known.
1 parent 218ccb1 commit cc2b6ce

File tree

2 files changed

+55
-24
lines changed

2 files changed

+55
-24
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6529,6 +6529,9 @@ ConstraintSystem::TypeMatchResult
65296529
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
65306530
TypeMatchOptions flags,
65316531
ConstraintLocatorBuilder locator) {
6532+
auto origType1 = type1;
6533+
auto origType2 = type2;
6534+
65326535
// If we have type variables that have been bound to fixed types, look through
65336536
// to the fixed type.
65346537
type1 = getFixedTypeRecursive(type1, flags, kind == ConstraintKind::Equal);
@@ -6792,11 +6795,32 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
67926795
return formUnsolvedResult();
67936796
}
67946797

6795-
// If either side is a tuple that has unresolved pack expansions,
6796-
// delay matching until more is inferred about type structure.
6797-
if (isTupleWithUnresolvedPackExpansion(desugar1) ||
6798-
isTupleWithUnresolvedPackExpansion(desugar2))
6799-
return formUnsolvedResult();
6798+
// If the original type on one side consisted of a tuple type with
6799+
// unresolved pack expansion(s), let's make sure that both sides are
6800+
// tuples to enable proper pack matching for situations like:
6801+
//
6802+
// `Int <conversion> (_: $T3)`
6803+
// where `$T3` is pack expansion of pattern type `$T2`
6804+
//
6805+
// `Int` should be wrapped in a one-element tuple to make sure
6806+
// that tuple matcher can form a pack expansion type that would
6807+
// match `$T3` and propagate `Pack{Int}` to `$T2`.
6808+
//
6809+
// This is also important for situations like: `$T2 conv (Int, $T_exp)`
6810+
// becuase expansion could be defaulted to an empty pack which means
6811+
// that under substitution that element would disappear and the type
6812+
// would be just `(Int)`.
6813+
if (isTupleWithUnresolvedPackExpansion(origType1) ||
6814+
isTupleWithUnresolvedPackExpansion(origType2)) {
6815+
if (desugar1->is<TupleType>() != desugar2->is<TupleType>()) {
6816+
return matchTypes(
6817+
desugar1->is<TupleType>() ? type1
6818+
: TupleType::get({type1}, getASTContext()),
6819+
desugar2->is<TupleType>() ? type2
6820+
: TupleType::get({type2}, getASTContext()),
6821+
kind, flags, locator);
6822+
}
6823+
}
68006824

68016825
llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
68026826

test/Constraints/pack_expansion_types.swift

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// RUN: %target-typecheck-verify-swift
22

33
func returnTuple1<each T>() -> (repeat each T) { fatalError() }
4-
// expected-note@-1 3 {{in call to function 'returnTuple1()'}}
4+
// expected-note@-1 {{in call to function 'returnTuple1()'}}
55

66
func returnTuple2<each T>() -> (Int, repeat each T) { fatalError() }
7-
// expected-note@-1 3 {{in call to function 'returnTuple2()'}}
7+
// expected-note@-1 2 {{in call to function 'returnTuple2()'}}
88

99
func returnTupleLabel1<each T>() -> (x: repeat each T) { fatalError() }
1010
// expected-error@-1 {{cannot use label with pack expansion tuple element}}
@@ -26,16 +26,10 @@ func returnTupleLabel6<each T, each U>() -> (Int, x: repeat each T, y: repeat ea
2626

2727
func concreteReturnTupleValid() {
2828
let _: () = returnTuple1()
29-
// FIXME: consider propagating 'Int' through the conversion constraint
30-
// as a binding for the parameter pack expanded in the tuple return type.
3129
let _: Int = returnTuple1()
32-
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
33-
// expected-error@-2 {{cannot convert value of type '(repeat each T)' to specified type 'Int'}}
3430
let _: (Int, String) = returnTuple1()
3531

3632
let _: Int = returnTuple2()
37-
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
38-
// expected-error@-2 {{cannot convert value of type '(Int, repeat each T)' to specified type 'Int'}}
3933
let _: (Int, String) = returnTuple2()
4034
let _: (Int, String, Float) = returnTuple2()
4135

@@ -72,8 +66,6 @@ func concreteReturnTupleValid() {
7266

7367
func concreteReturnTypeInvalid() {
7468
let _: Int = returnTuple1()
75-
// expected-error@-1 {{cannot convert value of type '(repeat each T)' to specified type 'Int'}}
76-
// expected-error@-2 {{generic parameter 'each T' could not be inferred}}
7769

7870
let _: () = returnTuple2()
7971
// expected-error@-1 {{'(Int, repeat each T)' is not convertible to '()', tuples have a different number of elements}}
@@ -218,28 +210,20 @@ func concreteReturnFunctionInvalid() {
218210
}
219211

220212
func patternInstantiationTupleTest1<each T>() -> (repeat Array<each T>) {}
221-
// expected-note@-1 3 {{in call to function 'patternInstantiationTupleTest1()'}}
213+
// expected-note@-1 2 {{in call to function 'patternInstantiationTupleTest1()'}}
222214
func patternInstantiationTupleTest2<each T, each U>() -> (repeat Dictionary<each T, each U>) {}
223-
// expected-note@-1 {{in call to function 'patternInstantiationTupleTest2()'}}
224215

225216
func patternInstantiationFunctionTest1<each T>() -> (repeat Array<each T>) -> () {}
226217
func patternInstantiationFunctionTest2<each T, each U>() -> (repeat Dictionary<each T, each U>) -> () {}
227218

228219
func patternInstantiationConcreteValid() {
229220
let _: () = patternInstantiationTupleTest1()
230-
// FIXME
231221
let _: Array<Int> = patternInstantiationTupleTest1()
232-
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
233-
// expected-error@-2 {{cannot convert value of type '(repeat Array<each T>)' to specified type 'Array<Int>'}}
234222
let _: (Array<Int>, Array<String>) = patternInstantiationTupleTest1()
235223
let _: (Array<Int>, Array<String>, Array<Float>) = patternInstantiationTupleTest1()
236224

237225
let _: () = patternInstantiationTupleTest2()
238-
// FIXME
239226
let _: Dictionary<Int, String> = patternInstantiationTupleTest2()
240-
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
241-
// expected-error@-2 {{generic parameter 'each U' could not be inferred}}
242-
// expected-error@-3 {{cannot convert value of type '(repeat Dictionary<each T, each U>)' to specified type 'Dictionary<Int, String>'}}
243227
let _: (Dictionary<Int, String>, Dictionary<Float, Bool>) = patternInstantiationTupleTest2()
244228
let _: (Dictionary<Int, String>, Dictionary<Float, Bool>, Dictionary<Double, Character>) = patternInstantiationTupleTest2()
245229

@@ -291,3 +275,26 @@ func patternInstantiationGenericInvalid<each T: Hashable>(t: repeat each T) {
291275

292276
let _: (repeat Array<each T>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{type of expression is ambiguous without more context}}
293277
}
278+
279+
// rdar://107996926 - Vanishing metatype of tuple not supported
280+
func test_one_element_tuple_vs_non_tuple_matching() {
281+
struct S {
282+
func test<each T>(_: (repeat each T).Type) -> (repeat each T) { fatalError() }
283+
func testVanishing<each T>(_: (Int, repeat each T)) {}
284+
}
285+
286+
let _ = S().test(Int.self) // Ok
287+
let _: Int = S().test(Int.self) // Ok
288+
let _ = S().test((Int, String).self) // Ok
289+
let _ = S().testVanishing(42) // Ok
290+
291+
do {
292+
struct V<T> {}
293+
294+
func test<each T>(_: V<(repeat each T)>?) {}
295+
func test<each T>(_: V<(repeat each T)>.Type) {}
296+
297+
test(V<Int>()) // Ok
298+
test(V<Int>.self) // Ok
299+
}
300+
}

0 commit comments

Comments
 (0)