Skip to content

Commit 85c1632

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 792d3c5 commit 85c1632

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
@@ -6546,6 +6546,9 @@ ConstraintSystem::TypeMatchResult
65466546
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
65476547
TypeMatchOptions flags,
65486548
ConstraintLocatorBuilder locator) {
6549+
auto origType1 = type1;
6550+
auto origType2 = type2;
6551+
65496552
// If we have type variables that have been bound to fixed types, look through
65506553
// to the fixed type.
65516554
type1 = getFixedTypeRecursive(type1, flags, kind == ConstraintKind::Equal);
@@ -6809,11 +6812,32 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
68096812
return formUnsolvedResult();
68106813
}
68116814

6812-
// If either side is a tuple that has unresolved pack expansions,
6813-
// delay matching until more is inferred about type structure.
6814-
if (isTupleWithUnresolvedPackExpansion(desugar1) ||
6815-
isTupleWithUnresolvedPackExpansion(desugar2))
6816-
return formUnsolvedResult();
6815+
// If the original type on one side consisted of a tuple type with
6816+
// unresolved pack expansion(s), let's make sure that both sides are
6817+
// tuples to enable proper pack matching for situations like:
6818+
//
6819+
// `Int <conversion> (_: $T3)`
6820+
// where `$T3` is pack expansion of pattern type `$T2`
6821+
//
6822+
// `Int` should be wrapped in a one-element tuple to make sure
6823+
// that tuple matcher can form a pack expansion type that would
6824+
// match `$T3` and propagate `Pack{Int}` to `$T2`.
6825+
//
6826+
// This is also important for situations like: `$T2 conv (Int, $T_exp)`
6827+
// becuase expansion could be defaulted to an empty pack which means
6828+
// that under substitution that element would disappear and the type
6829+
// would be just `(Int)`.
6830+
if (isTupleWithUnresolvedPackExpansion(origType1) ||
6831+
isTupleWithUnresolvedPackExpansion(origType2)) {
6832+
if (desugar1->is<TupleType>() != desugar2->is<TupleType>()) {
6833+
return matchTypes(
6834+
desugar1->is<TupleType>() ? type1
6835+
: TupleType::get({type1}, getASTContext()),
6836+
desugar2->is<TupleType>() ? type2
6837+
: TupleType::get({type2}, getASTContext()),
6838+
kind, flags, locator);
6839+
}
6840+
}
68176841

68186842
llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
68196843

test/Constraints/pack_expansion_types.swift

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// REQUIRES: asserts
44

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

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

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

2929
func concreteReturnTupleValid() {
3030
let _: () = returnTuple1()
31-
// FIXME: consider propagating 'Int' through the conversion constraint
32-
// as a binding for the parameter pack expanded in the tuple return type.
3331
let _: Int = returnTuple1()
34-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
35-
// expected-error@-2 {{cannot convert value of type '(repeat each T)' to specified type 'Int'}}
3632
let _: (Int, String) = returnTuple1()
3733

3834
let _: Int = returnTuple2()
39-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
40-
// expected-error@-2 {{cannot convert value of type '(Int, repeat each T)' to specified type 'Int'}}
4135
let _: (Int, String) = returnTuple2()
4236
let _: (Int, String, Float) = returnTuple2()
4337

@@ -74,8 +68,6 @@ func concreteReturnTupleValid() {
7468

7569
func concreteReturnTypeInvalid() {
7670
let _: Int = returnTuple1()
77-
// expected-error@-1 {{cannot convert value of type '(repeat each T)' to specified type 'Int'}}
78-
// expected-error@-2 {{generic parameter 'T' could not be inferred}}
7971

8072
let _: () = returnTuple2()
8173
// expected-error@-1 {{'(Int, repeat each T)' is not convertible to '()', tuples have a different number of elements}}
@@ -220,28 +212,20 @@ func concreteReturnFunctionInvalid() {
220212
}
221213

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

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

230221
func patternInstantiationConcreteValid() {
231222
let _: () = patternInstantiationTupleTest1()
232-
// FIXME
233223
let _: Array<Int> = patternInstantiationTupleTest1()
234-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
235-
// expected-error@-2 {{cannot convert value of type '(repeat Array<each T>)' to specified type 'Array<Int>'}}
236224
let _: (Array<Int>, Array<String>) = patternInstantiationTupleTest1()
237225
let _: (Array<Int>, Array<String>, Array<Float>) = patternInstantiationTupleTest1()
238226

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

@@ -293,3 +277,26 @@ func patternInstantiationGenericInvalid<each T: Hashable>(t: repeat each T) {
293277

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

0 commit comments

Comments
 (0)