From ac5884a54f9e5c92bd36844c9e6198e43e413117 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:01:40 -0700 Subject: [PATCH] cherry pick "No `this` type arguments in base constraints (#54536)" to release-5.1 (#54814) Co-authored-by: Anders Hejlsberg --- src/compiler/checker.ts | 34 +++-- .../complexRecursiveCollections.errors.txt | 12 +- .../reference/largeTupleTypes.symbols | 118 ++++++++++++++++++ .../baselines/reference/largeTupleTypes.types | 32 +++++ .../reference/mergedDeclarations7.errors.txt | 4 +- tests/cases/compiler/largeTupleTypes.ts | 15 +++ 6 files changed, 188 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/largeTupleTypes.symbols create mode 100644 tests/baselines/reference/largeTupleTypes.types create mode 100644 tests/cases/compiler/largeTupleTypes.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ea2abe9c2868..eb07e8f166baf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12499,10 +12499,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getObjectFlags(type) & ObjectFlags.Reference) { const target = (type as TypeReference).target; const typeArguments = getTypeArguments(type as TypeReference); - if (length(target.typeParameters) === length(typeArguments)) { - const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])); - return needApparentType ? getApparentType(ref) : ref; - } + return length(target.typeParameters) === length(typeArguments) ? createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])) : type; } else if (type.flags & TypeFlags.Intersection) { const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); @@ -12511,10 +12508,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return needApparentType ? getApparentType(type) : type; } - function getThisArgument(type: Type) { - return getObjectFlags(type) & ObjectFlags.Reference && length(getTypeArguments(type as TypeReference)) > getTypeReferenceArity(type as TypeReference) ? last(getTypeArguments(type as TypeReference)) : type; - } - function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) { let mapper: TypeMapper | undefined; let members: SymbolTable; @@ -13696,7 +13689,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type.resolvedBaseConstraint; } const stack: object[] = []; - return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), getThisArgument(type)); + return type.resolvedBaseConstraint = getImmediateBaseConstraint(type); function getImmediateBaseConstraint(t: Type): Type { if (!t.immediateBaseConstraint) { @@ -13802,8 +13795,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We substitute constraints for variadic elements only when the constraints are array types or // non-variadic tuple types as we want to avoid further (possibly unbounded) recursion. const newElements = map(getElementTypes(t), (v, i) => { - const constraint = t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v; - return constraint && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v; + const constraint = v.flags & TypeFlags.TypeParameter && t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v; + return constraint !== v && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v; }); return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations); } @@ -13811,8 +13804,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getApparentTypeOfIntersectionType(type: IntersectionType) { - return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*needApparentType*/ true)); + function getApparentTypeOfIntersectionType(type: IntersectionType, thisArgument: Type) { + return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true)); } function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { @@ -13890,9 +13883,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * type itself. */ function getApparentType(type: Type): Type { - const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType; - return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : - t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) : + const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type; + const objectFlags = getObjectFlags(t); + return objectFlags & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : + objectFlags & ObjectFlags.Reference && t !== type ? getTypeWithThisArgument(t, type) : + t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType, type) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : @@ -21570,9 +21565,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const c = target as ConditionalType; // We check for a relationship to a conditional type target only when the conditional type has no - // 'infer' positions and is not distributive or is distributive but doesn't reference the check type - // parameter in either of the result types. - if (!c.root.inferTypeParameters && !isDistributionDependent(c.root)) { + // 'infer' positions, is not distributive or is distributive but doesn't reference the check type + // parameter in either of the result types, and the source isn't an instantiation of the same + // conditional type (as happens when computing variance). + if (!c.root.inferTypeParameters && !isDistributionDependent(c.root) && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root)) { // Check if the conditional is always true or always false but still deferred for distribution purposes. const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); diff --git a/tests/baselines/reference/complexRecursiveCollections.errors.txt b/tests/baselines/reference/complexRecursiveCollections.errors.txt index 91745b84e384d..cd88e596fd160 100644 --- a/tests/baselines/reference/complexRecursiveCollections.errors.txt +++ b/tests/baselines/reference/complexRecursiveCollections.errors.txt @@ -1,15 +1,15 @@ tests/cases/compiler/immutable.ts(341,22): error TS2430: Interface 'Keyed' incorrectly extends interface 'Collection'. The types returned by 'toSeq()' are incompatible between these types. Type 'Keyed' is not assignable to type 'this'. - 'this' could be instantiated with an arbitrary type which could be unrelated to 'Keyed'. + 'Keyed' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Keyed'. tests/cases/compiler/immutable.ts(359,22): error TS2430: Interface 'Indexed' incorrectly extends interface 'Collection'. The types returned by 'toSeq()' are incompatible between these types. Type 'Indexed' is not assignable to type 'this'. - 'this' could be instantiated with an arbitrary type which could be unrelated to 'Indexed'. + 'Indexed' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Indexed'. tests/cases/compiler/immutable.ts(391,22): error TS2430: Interface 'Set' incorrectly extends interface 'Collection'. The types returned by 'toSeq()' are incompatible between these types. Type 'Set' is not assignable to type 'this'. - 'this' could be instantiated with an arbitrary type which could be unrelated to 'Set'. + 'Set' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Set'. ==== tests/cases/compiler/complex.ts (0 errors) ==== @@ -379,7 +379,7 @@ tests/cases/compiler/immutable.ts(391,22): error TS2430: Interface 'Set' inco !!! error TS2430: Interface 'Keyed' incorrectly extends interface 'Collection'. !!! error TS2430: The types returned by 'toSeq()' are incompatible between these types. !!! error TS2430: Type 'Keyed' is not assignable to type 'this'. -!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Keyed'. +!!! error TS2430: 'Keyed' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Keyed'. toJS(): Object; toJSON(): { [key: string]: V }; toSeq(): Seq.Keyed; @@ -402,7 +402,7 @@ tests/cases/compiler/immutable.ts(391,22): error TS2430: Interface 'Set' inco !!! error TS2430: Interface 'Indexed' incorrectly extends interface 'Collection'. !!! error TS2430: The types returned by 'toSeq()' are incompatible between these types. !!! error TS2430: Type 'Indexed' is not assignable to type 'this'. -!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Indexed'. +!!! error TS2430: 'Indexed' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Indexed'. toJS(): Array; toJSON(): Array; // Reading values @@ -439,7 +439,7 @@ tests/cases/compiler/immutable.ts(391,22): error TS2430: Interface 'Set' inco !!! error TS2430: Interface 'Set' incorrectly extends interface 'Collection'. !!! error TS2430: The types returned by 'toSeq()' are incompatible between these types. !!! error TS2430: Type 'Set' is not assignable to type 'this'. -!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Set'. +!!! error TS2430: 'Set' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Set'. toJS(): Array; toJSON(): Array; toSeq(): Seq.Set; diff --git a/tests/baselines/reference/largeTupleTypes.symbols b/tests/baselines/reference/largeTupleTypes.symbols new file mode 100644 index 0000000000000..495f96210472d --- /dev/null +++ b/tests/baselines/reference/largeTupleTypes.symbols @@ -0,0 +1,118 @@ +=== tests/cases/compiler/largeTupleTypes.ts === +// Repro from #54491 + +type UnshiftTuple = T extends [T[0], ...infer Tail] ? Tail : never; +>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18)) +>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 2, 67)) +>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 2, 67)) + +type ExpandSmallerTuples = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples : []; +>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25)) +>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 3, 74)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25)) +>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89)) +>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 3, 74)) + +type Shift> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; +>Shift : Symbol(Shift, Decl(largeTupleTypes.ts, 3, 118)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>args : Symbol(args, Decl(largeTupleTypes.ts, 4, 37)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11)) +>args : Symbol(args, Decl(largeTupleTypes.ts, 4, 67)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11)) +>R : Symbol(R, Decl(largeTupleTypes.ts, 4, 91)) +>R : Symbol(R, Decl(largeTupleTypes.ts, 4, 91)) + +type GrowExpRev, N extends number, P extends Array>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift

>; +>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37)) +>Shift : Symbol(Shift, Decl(largeTupleTypes.ts, 3, 118)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55)) + +type GrowExp, N extends number, P extends Array>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev; +>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34)) +>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52)) +>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116)) +>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34)) +>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52)) + +type Tuple = number extends N ? Array : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>; +>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11)) +>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11)) +>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13)) + +declare class ArrayValidator { +>ArrayValidator : Symbol(ArrayValidator, Decl(largeTupleTypes.ts, 7, 125)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 9, 29)) +>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49)) +>T : Symbol(T, Decl(largeTupleTypes.ts, 9, 29)) + + lengthRange(start: S, endBefore: E): ArrayValidator]>>, ExpandSmallerTuples]>>>>; +>lengthRange : Symbol(ArrayValidator.lengthRange, Decl(largeTupleTypes.ts, 9, 66)) +>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16)) +>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33)) +>start : Symbol(start, Decl(largeTupleTypes.ts, 10, 52)) +>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16)) +>endBefore : Symbol(endBefore, Decl(largeTupleTypes.ts, 10, 61)) +>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33)) +>ArrayValidator : Symbol(ArrayValidator, Decl(largeTupleTypes.ts, 7, 125)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89)) +>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0)) +>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178)) +>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49)) +>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33)) +>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89)) +>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0)) +>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178)) +>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49)) +>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16)) +} + diff --git a/tests/baselines/reference/largeTupleTypes.types b/tests/baselines/reference/largeTupleTypes.types new file mode 100644 index 0000000000000..d369a43ae3c01 --- /dev/null +++ b/tests/baselines/reference/largeTupleTypes.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/largeTupleTypes.ts === +// Repro from #54491 + +type UnshiftTuple = T extends [T[0], ...infer Tail] ? Tail : never; +>UnshiftTuple : UnshiftTuple + +type ExpandSmallerTuples = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples : []; +>ExpandSmallerTuples : ExpandSmallerTuples + +type Shift> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; +>Shift : Shift +>args : A +>args : [A[0], ...R] + +type GrowExpRev, N extends number, P extends Array>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift

>; +>GrowExpRev : GrowExpRev + +type GrowExp, N extends number, P extends Array>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev; +>GrowExp : GrowExp + +type Tuple = number extends N ? Array : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>; +>Tuple : Tuple + +declare class ArrayValidator { +>ArrayValidator : ArrayValidator + + lengthRange(start: S, endBefore: E): ArrayValidator]>>, ExpandSmallerTuples]>>>>; +>lengthRange : (start: S, endBefore: E) => ArrayValidator]>>, ExpandSmallerTuples]>>>> +>start : S +>endBefore : E +} + diff --git a/tests/baselines/reference/mergedDeclarations7.errors.txt b/tests/baselines/reference/mergedDeclarations7.errors.txt index 9ab164ad0356d..b9e924d2ebcc9 100644 --- a/tests/baselines/reference/mergedDeclarations7.errors.txt +++ b/tests/baselines/reference/mergedDeclarations7.errors.txt @@ -1,7 +1,7 @@ tests/cases/compiler/test.ts(4,5): error TS2322: Type 'PassportStatic' is not assignable to type 'Passport'. The types returned by 'use()' are incompatible between these types. Type 'PassportStatic' is not assignable to type 'this'. - 'this' could be instantiated with an arbitrary type which could be unrelated to 'PassportStatic'. + 'PassportStatic' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Passport'. ==== tests/cases/compiler/passport.d.ts (0 errors) ==== @@ -29,4 +29,4 @@ tests/cases/compiler/test.ts(4,5): error TS2322: Type 'PassportStatic' is not as !!! error TS2322: Type 'PassportStatic' is not assignable to type 'Passport'. !!! error TS2322: The types returned by 'use()' are incompatible between these types. !!! error TS2322: Type 'PassportStatic' is not assignable to type 'this'. -!!! error TS2322: 'this' could be instantiated with an arbitrary type which could be unrelated to 'PassportStatic'. \ No newline at end of file +!!! error TS2322: 'PassportStatic' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Passport'. \ No newline at end of file diff --git a/tests/cases/compiler/largeTupleTypes.ts b/tests/cases/compiler/largeTupleTypes.ts new file mode 100644 index 0000000000000..84ddd8d2372c2 --- /dev/null +++ b/tests/cases/compiler/largeTupleTypes.ts @@ -0,0 +1,15 @@ +// @strict: true +// @noEmit: true + +// Repro from #54491 + +type UnshiftTuple = T extends [T[0], ...infer Tail] ? Tail : never; +type ExpandSmallerTuples = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples : []; +type Shift> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; +type GrowExpRev, N extends number, P extends Array>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift

>; +type GrowExp, N extends number, P extends Array>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev; +type Tuple = number extends N ? Array : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>; + +declare class ArrayValidator { + lengthRange(start: S, endBefore: E): ArrayValidator]>>, ExpandSmallerTuples]>>>>; +}