Infer fixed-size tuples from infer type parameters with extends clauses at variadic positions (#51157)

* Infer fixed-size tuples from infer type parameters with extends clauses at variadic positions

* Improve the fix to handle tuples with leading variadic elements

* Fixed indentation

* Infer rest element following a variadic element with a fixed-size constraint

* Infer rest element preceding a variadic element with a fixed-size constraint

* Rewrite the test to avoid accidental union reductions
This commit is contained in:
Mateusz Burzyński
2023-01-03 19:18:09 +01:00
committed by GitHub
parent 1a943d7b68
commit 31d1d63fc8
4 changed files with 370 additions and 7 deletions

View File

@@ -24303,13 +24303,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
else {
const middleLength = targetArity - startLength - endLength;
if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...T, ...U] and source is tuple type
const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
if (targetInfo && targetInfo.impliedArity !== undefined) {
// Infer slices from source based on implied arity of T.
inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
if (middleLength === 2) {
if (elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...T, ...U] and source is tuple type
const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
if (targetInfo && targetInfo.impliedArity !== undefined) {
// Infer slices from source based on implied arity of T.
inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
}
}
else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) {
// Middle of target is [...T, ...rest] and source is tuple type
// if T is constrained by a fixed-size tuple we might be able to use its arity to infer T
const param = getInferenceInfoForType(elementTypes[startLength])?.typeParameter;
const constraint = param && getBaseConstraintOfType(param);
if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) {
const impliedArity = constraint.target.fixedLength;
inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]);
inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]);
}
}
else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...rest, ...T] and source is tuple type
// if T is constrained by a fixed-size tuple we might be able to use its arity to infer T
const param = getInferenceInfoForType(elementTypes[startLength + 1])?.typeParameter;
const constraint = param && getBaseConstraintOfType(param);
if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) {
const impliedArity = constraint.target.fixedLength;
const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed);
const startIndex = endIndex - impliedArity;
const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex),
/*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex));
inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]);
inferFromTypes(trailingSlice, elementTypes[startLength + 1]);
}
}
}
else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) {

View File

@@ -0,0 +1,160 @@
=== tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts ===
// repro #51138
type SubTup2FixedLength<T extends unknown[]> = T extends [
>SubTup2FixedLength : Symbol(SubTup2FixedLength, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 0, 0))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 2, 24))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 2, 24))
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 3, 10))
any
]
? B
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 3, 10))
: never;
type SubTup2FixedLengthTest = SubTup2FixedLength<[a: 0, b: 1, c: 2]>;
>SubTup2FixedLengthTest : Symbol(SubTup2FixedLengthTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 7, 10))
>SubTup2FixedLength : Symbol(SubTup2FixedLength, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 0, 0))
type SubTup2Variadic<T extends unknown[]> = T extends [
>SubTup2Variadic : Symbol(SubTup2Variadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 9, 69))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 11, 21))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 11, 21))
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 12, 10))
...any
]
? B
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 12, 10))
: never;
type SubTup2VariadicTest = SubTup2Variadic<[a: 0, b: 1, ...c: 2[]]>;
>SubTup2VariadicTest : Symbol(SubTup2VariadicTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 16, 10))
>SubTup2Variadic : Symbol(SubTup2Variadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 9, 69))
type SubTup2VariadicTest2 = SubTup2Variadic<[a: 0, b: 1, c: 2, ...d: 3[]]>;
>SubTup2VariadicTest2 : Symbol(SubTup2VariadicTest2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 18, 68))
>SubTup2Variadic : Symbol(SubTup2Variadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 9, 69))
type SubTup2VariadicAndRest<T extends unknown[]> = T extends [
>SubTup2VariadicAndRest : Symbol(SubTup2VariadicAndRest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 19, 75))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 21, 28))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 21, 28))
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 22, 12))
...(infer C)[]
>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 23, 13))
]
? [...B, ...[C]]
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 22, 12))
>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 23, 13))
: never;
type SubTup2VariadicAndRestTest = SubTup2VariadicAndRest<[a: 0, b: 1, ...c: 2[]]>;
>SubTup2VariadicAndRestTest : Symbol(SubTup2VariadicAndRestTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 26, 12))
>SubTup2VariadicAndRest : Symbol(SubTup2VariadicAndRest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 19, 75))
type SubTup2TrailingVariadic<T extends unknown[]> = T extends [
>SubTup2TrailingVariadic : Symbol(SubTup2TrailingVariadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 28, 82))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 30, 29))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 30, 29))
...any,
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 32, 10))
]
? B
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 32, 10))
: never;
type SubTup2TrailingVariadicTest = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2]>;
>SubTup2TrailingVariadicTest : Symbol(SubTup2TrailingVariadicTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 35, 10))
>SubTup2TrailingVariadic : Symbol(SubTup2TrailingVariadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 28, 82))
type SubTup2TrailingVariadicTest2 = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2, d: 3]>;
>SubTup2TrailingVariadicTest2 : Symbol(SubTup2TrailingVariadicTest2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 37, 84))
>SubTup2TrailingVariadic : Symbol(SubTup2TrailingVariadic, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 28, 82))
type SubTup2RestAndTrailingVariadic2<T extends unknown[]> = T extends [
>SubTup2RestAndTrailingVariadic2 : Symbol(SubTup2RestAndTrailingVariadic2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 38, 91))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 40, 37))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 40, 37))
...(infer C)[],
>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 41, 13))
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 42, 12))
]
? [C, ...B]
>C : Symbol(C, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 41, 13))
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 42, 12))
: never;
type SubTup2RestAndTrailingVariadic2Test = SubTup2RestAndTrailingVariadic2<[...a: 0[], b: 1, c: 2]>;
>SubTup2RestAndTrailingVariadic2Test : Symbol(SubTup2RestAndTrailingVariadic2Test, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 45, 12))
>SubTup2RestAndTrailingVariadic2 : Symbol(SubTup2RestAndTrailingVariadic2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 38, 91))
type SubTup2VariadicWithLeadingFixedElements<T extends unknown[]> = T extends [
>SubTup2VariadicWithLeadingFixedElements : Symbol(SubTup2VariadicWithLeadingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 47, 100))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 49, 45))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 49, 45))
any,
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 51, 10))
...any
]
? B
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 51, 10))
: never;
type SubTup2VariadicWithLeadingFixedElementsTest = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, ...d: 3[]]>;
>SubTup2VariadicWithLeadingFixedElementsTest : Symbol(SubTup2VariadicWithLeadingFixedElementsTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 55, 10))
>SubTup2VariadicWithLeadingFixedElements : Symbol(SubTup2VariadicWithLeadingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 47, 100))
type SubTup2VariadicWithLeadingFixedElementsTest2 = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, d: 3, ...e: 4[]]>;
>SubTup2VariadicWithLeadingFixedElementsTest2 : Symbol(SubTup2VariadicWithLeadingFixedElementsTest2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 57, 122))
>SubTup2VariadicWithLeadingFixedElements : Symbol(SubTup2VariadicWithLeadingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 47, 100))
type SubTup2TrailingVariadicWithTrailingFixedElements<T extends unknown[]> = T extends [
>SubTup2TrailingVariadicWithTrailingFixedElements : Symbol(SubTup2TrailingVariadicWithTrailingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 58, 129))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 60, 54))
>T : Symbol(T, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 60, 54))
...any,
...infer B extends [any, any],
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 62, 10))
any,
]
? B
>B : Symbol(B, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 62, 10))
: never;
type SubTup2TrailingVariadicWithTrailingFixedElementsTest = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3]>;
>SubTup2TrailingVariadicWithTrailingFixedElementsTest : Symbol(SubTup2TrailingVariadicWithTrailingFixedElementsTest, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 66, 10))
>SubTup2TrailingVariadicWithTrailingFixedElements : Symbol(SubTup2TrailingVariadicWithTrailingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 58, 129))
type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3, e: 4]>;
>SubTup2TrailingVariadicWithTrailingFixedElementsTest2 : Symbol(SubTup2TrailingVariadicWithTrailingFixedElementsTest2, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 68, 140))
>SubTup2TrailingVariadicWithTrailingFixedElements : Symbol(SubTup2TrailingVariadicWithTrailingFixedElements, Decl(inferTypesWithFixedTupleExtendsAtVariadicPosition.ts, 58, 129))

View File

@@ -0,0 +1,101 @@
=== tests/cases/compiler/inferTypesWithFixedTupleExtendsAtVariadicPosition.ts ===
// repro #51138
type SubTup2FixedLength<T extends unknown[]> = T extends [
>SubTup2FixedLength : SubTup2FixedLength<T>
...infer B extends [any, any],
any
]
? B
: never;
type SubTup2FixedLengthTest = SubTup2FixedLength<[a: 0, b: 1, c: 2]>;
>SubTup2FixedLengthTest : [a: 0, b: 1]
type SubTup2Variadic<T extends unknown[]> = T extends [
>SubTup2Variadic : SubTup2Variadic<T>
...infer B extends [any, any],
...any
]
? B
: never;
type SubTup2VariadicTest = SubTup2Variadic<[a: 0, b: 1, ...c: 2[]]>;
>SubTup2VariadicTest : [a: 0, b: 1]
type SubTup2VariadicTest2 = SubTup2Variadic<[a: 0, b: 1, c: 2, ...d: 3[]]>;
>SubTup2VariadicTest2 : [a: 0, b: 1]
type SubTup2VariadicAndRest<T extends unknown[]> = T extends [
>SubTup2VariadicAndRest : SubTup2VariadicAndRest<T>
...infer B extends [any, any],
...(infer C)[]
]
? [...B, ...[C]]
: never;
type SubTup2VariadicAndRestTest = SubTup2VariadicAndRest<[a: 0, b: 1, ...c: 2[]]>;
>SubTup2VariadicAndRestTest : [0, 1, 2]
type SubTup2TrailingVariadic<T extends unknown[]> = T extends [
>SubTup2TrailingVariadic : SubTup2TrailingVariadic<T>
...any,
...infer B extends [any, any],
]
? B
: never;
type SubTup2TrailingVariadicTest = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2]>;
>SubTup2TrailingVariadicTest : [b: 1, c: 2]
type SubTup2TrailingVariadicTest2 = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2, d: 3]>;
>SubTup2TrailingVariadicTest2 : [c: 2, d: 3]
type SubTup2RestAndTrailingVariadic2<T extends unknown[]> = T extends [
>SubTup2RestAndTrailingVariadic2 : SubTup2RestAndTrailingVariadic2<T>
...(infer C)[],
...infer B extends [any, any],
]
? [C, ...B]
: never;
type SubTup2RestAndTrailingVariadic2Test = SubTup2RestAndTrailingVariadic2<[...a: 0[], b: 1, c: 2]>;
>SubTup2RestAndTrailingVariadic2Test : [0, 1, 2]
type SubTup2VariadicWithLeadingFixedElements<T extends unknown[]> = T extends [
>SubTup2VariadicWithLeadingFixedElements : SubTup2VariadicWithLeadingFixedElements<T>
any,
...infer B extends [any, any],
...any
]
? B
: never;
type SubTup2VariadicWithLeadingFixedElementsTest = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, ...d: 3[]]>;
>SubTup2VariadicWithLeadingFixedElementsTest : [b: 1, c: 2]
type SubTup2VariadicWithLeadingFixedElementsTest2 = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, d: 3, ...e: 4[]]>;
>SubTup2VariadicWithLeadingFixedElementsTest2 : [b: 1, c: 2]
type SubTup2TrailingVariadicWithTrailingFixedElements<T extends unknown[]> = T extends [
>SubTup2TrailingVariadicWithTrailingFixedElements : SubTup2TrailingVariadicWithTrailingFixedElements<T>
...any,
...infer B extends [any, any],
any,
]
? B
: never;
type SubTup2TrailingVariadicWithTrailingFixedElementsTest = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3]>;
>SubTup2TrailingVariadicWithTrailingFixedElementsTest : [b: 1, c: 2]
type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3, e: 4]>;
>SubTup2TrailingVariadicWithTrailingFixedElementsTest2 : [c: 2, d: 3]

View File

@@ -0,0 +1,73 @@
// @strict: true
// @noEmit: true
// repro #51138
type SubTup2FixedLength<T extends unknown[]> = T extends [
...infer B extends [any, any],
any
]
? B
: never;
type SubTup2FixedLengthTest = SubTup2FixedLength<[a: 0, b: 1, c: 2]>;
type SubTup2Variadic<T extends unknown[]> = T extends [
...infer B extends [any, any],
...any
]
? B
: never;
type SubTup2VariadicTest = SubTup2Variadic<[a: 0, b: 1, ...c: 2[]]>;
type SubTup2VariadicTest2 = SubTup2Variadic<[a: 0, b: 1, c: 2, ...d: 3[]]>;
type SubTup2VariadicAndRest<T extends unknown[]> = T extends [
...infer B extends [any, any],
...(infer C)[]
]
? [...B, ...[C]]
: never;
type SubTup2VariadicAndRestTest = SubTup2VariadicAndRest<[a: 0, b: 1, ...c: 2[]]>;
type SubTup2TrailingVariadic<T extends unknown[]> = T extends [
...any,
...infer B extends [any, any],
]
? B
: never;
type SubTup2TrailingVariadicTest = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2]>;
type SubTup2TrailingVariadicTest2 = SubTup2TrailingVariadic<[...a: 0[], b: 1, c: 2, d: 3]>;
type SubTup2RestAndTrailingVariadic2<T extends unknown[]> = T extends [
...(infer C)[],
...infer B extends [any, any],
]
? [C, ...B]
: never;
type SubTup2RestAndTrailingVariadic2Test = SubTup2RestAndTrailingVariadic2<[...a: 0[], b: 1, c: 2]>;
type SubTup2VariadicWithLeadingFixedElements<T extends unknown[]> = T extends [
any,
...infer B extends [any, any],
...any
]
? B
: never;
type SubTup2VariadicWithLeadingFixedElementsTest = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, ...d: 3[]]>;
type SubTup2VariadicWithLeadingFixedElementsTest2 = SubTup2VariadicWithLeadingFixedElements<[a: 0, b: 1, c: 2, d: 3, ...e: 4[]]>;
type SubTup2TrailingVariadicWithTrailingFixedElements<T extends unknown[]> = T extends [
...any,
...infer B extends [any, any],
any,
]
? B
: never;
type SubTup2TrailingVariadicWithTrailingFixedElementsTest = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3]>;
type SubTup2TrailingVariadicWithTrailingFixedElementsTest2 = SubTup2TrailingVariadicWithTrailingFixedElements<[...a: 0[], b: 1, c: 2, d: 3, e: 4]>;