From 005d5946c089b8319470cbea96db94cc6bd601bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 11 Feb 2026 20:08:57 +0100 Subject: [PATCH] Fixed a crash related to variadic tuple elements with intersections containing `InstantiableNonPrimitive` --- src/compiler/checker.ts | 6 +++++- .../reference/recursiveConditionalCrash5.errors.txt | 10 ++++++++++ .../reference/recursiveConditionalCrash5.symbols | 13 +++++++++++++ .../reference/recursiveConditionalCrash5.types | 9 +++++++++ tests/cases/compiler/recursiveConditionalCrash5.ts | 6 ++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/recursiveConditionalCrash5.errors.txt create mode 100644 tests/baselines/reference/recursiveConditionalCrash5.symbols create mode 100644 tests/baselines/reference/recursiveConditionalCrash5.types create mode 100644 tests/cases/compiler/recursiveConditionalCrash5.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8fa3c4fce2a4a..fb5fdf6069354 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17965,7 +17965,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Any) { addElement(type, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); } - else if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) { + else if (someContainedType(type, t => !!(t.flags & TypeFlags.InstantiableNonPrimitive) || isGenericMappedType(type))) { // Generic variadic elements stay as they are. addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]); } @@ -28515,6 +28515,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type.flags & TypeFlags.Union ? every((type as UnionType).types, f) : f(type); } + function someContainedType(type: Type, f: (t: Type) => boolean): boolean { + return type.flags & TypeFlags.UnionOrIntersection ? some((type as UnionOrIntersectionType).types, f) : f(type); + } + function everyContainedType(type: Type, f: (t: Type) => boolean): boolean { return type.flags & TypeFlags.UnionOrIntersection ? every((type as UnionOrIntersectionType).types, f) : f(type); } diff --git a/tests/baselines/reference/recursiveConditionalCrash5.errors.txt b/tests/baselines/reference/recursiveConditionalCrash5.errors.txt new file mode 100644 index 0000000000000..ac99cf2a6d542 --- /dev/null +++ b/tests/baselines/reference/recursiveConditionalCrash5.errors.txt @@ -0,0 +1,10 @@ +recursiveConditionalCrash5.ts(3,60): error TS2589: Type instantiation is excessively deep and possibly infinite. + + +==== recursiveConditionalCrash5.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/63040 + + type StringTreeArrayAsTuple = (T extends [...infer R] ? [...StringTreeArrayAsTuple] : never) & boolean; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2589: Type instantiation is excessively deep and possibly infinite. + \ No newline at end of file diff --git a/tests/baselines/reference/recursiveConditionalCrash5.symbols b/tests/baselines/reference/recursiveConditionalCrash5.symbols new file mode 100644 index 0000000000000..088577dcd7b43 --- /dev/null +++ b/tests/baselines/reference/recursiveConditionalCrash5.symbols @@ -0,0 +1,13 @@ +//// [tests/cases/compiler/recursiveConditionalCrash5.ts] //// + +=== recursiveConditionalCrash5.ts === +// https://github.com/microsoft/TypeScript/issues/63040 + +type StringTreeArrayAsTuple = (T extends [...infer R] ? [...StringTreeArrayAsTuple] : never) & boolean; +>StringTreeArrayAsTuple : Symbol(StringTreeArrayAsTuple, Decl(recursiveConditionalCrash5.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 2, 28)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 2, 28)) +>R : Symbol(R, Decl(recursiveConditionalCrash5.ts, 2, 53)) +>StringTreeArrayAsTuple : Symbol(StringTreeArrayAsTuple, Decl(recursiveConditionalCrash5.ts, 0, 0)) +>R : Symbol(R, Decl(recursiveConditionalCrash5.ts, 2, 53)) + diff --git a/tests/baselines/reference/recursiveConditionalCrash5.types b/tests/baselines/reference/recursiveConditionalCrash5.types new file mode 100644 index 0000000000000..d920776cd72ed --- /dev/null +++ b/tests/baselines/reference/recursiveConditionalCrash5.types @@ -0,0 +1,9 @@ +//// [tests/cases/compiler/recursiveConditionalCrash5.ts] //// + +=== recursiveConditionalCrash5.ts === +// https://github.com/microsoft/TypeScript/issues/63040 + +type StringTreeArrayAsTuple = (T extends [...infer R] ? [...StringTreeArrayAsTuple] : never) & boolean; +>StringTreeArrayAsTuple : StringTreeArrayAsTuple +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/compiler/recursiveConditionalCrash5.ts b/tests/cases/compiler/recursiveConditionalCrash5.ts new file mode 100644 index 0000000000000..87641a5ca9277 --- /dev/null +++ b/tests/cases/compiler/recursiveConditionalCrash5.ts @@ -0,0 +1,6 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/63040 + +type StringTreeArrayAsTuple = (T extends [...infer R] ? [...StringTreeArrayAsTuple] : never) & boolean;