From 77d63f529a929a8676d813619e72b1e86ce0e4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 11 Sep 2026 10:12:27 +0200 Subject: [PATCH] Fixed a crash related to variadic tuple elements with intersections containing `InstantiableNonPrimitive` --- tsc/internal/checker/checker.go | 11 ++++++++++- .../compiler/recursiveConditionalCrash5.errors.txt | 10 ++++++++++ .../compiler/recursiveConditionalCrash5.symbols | 13 +++++++++++++ .../compiler/recursiveConditionalCrash5.types | 8 ++++++++ .../cases/compiler/recursiveConditionalCrash5.ts | 6 ++++++ 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types create mode 100644 tsc/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index ca77e97af8547..e3215baa00120 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -23707,7 +23707,9 @@ func (n *TupleNormalizer) normalize(c *Checker, elementTypes []*Type, elementInf if info.flags&ElementFlagsVariadic != 0 { if t.flags&TypeFlagsAny != 0 { n.add(t, TupleElementInfo{flags: ElementFlagsRest, labeledDeclaration: info.labeledDeclaration}) - } else if t.flags&TypeFlagsInstantiableNonPrimitive != 0 || c.isGenericMappedType(t) { + } else if someContainedType(t, func(t *Type) bool { + return t.flags&TypeFlagsInstantiableNonPrimitive != 0 || c.isGenericMappedType(t) + }) { // Generic variadic elements stay as they are. n.add(t, info) } else if isTupleType(t) { @@ -26893,6 +26895,13 @@ func everyType(t *Type, f func(*Type) bool) bool { return f(t) } +func someContainedType(t *Type, f func(*Type) bool) bool { + if t.flags&TypeFlagsUnionOrIntersection != 0 { + return core.Some(t.Types(), f) + } + return f(t) +} + func everyContainedType(t *Type, f func(*Type) bool) bool { if t.flags&TypeFlagsUnionOrIntersection != 0 { return core.Every(t.Types(), f) diff --git a/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt b/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt new file mode 100644 index 0000000000000..ac99cf2a6d542 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/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/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols b/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols new file mode 100644 index 0000000000000..088577dcd7b43 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/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/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types b/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types new file mode 100644 index 0000000000000..671d71e3f6470 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types @@ -0,0 +1,8 @@ +//// [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/tsc/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts b/tsc/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts new file mode 100644 index 0000000000000..87641a5ca9277 --- /dev/null +++ b/tsc/testdata/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;