diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 5bf47a1049..b2fb6879ed 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -21508,6 +21508,9 @@ func (c *Checker) instantiateTypeWithAlias(t *Type, m *TypeMapper, alias *TypeAl // or expression. There is a very high likelihood we're dealing with a combination of infinite generic types // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. c.error(c.currentNode, diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite) + // Set this to a max value to "propagate" the error through any further instantiations within the currently checked node. + // This can skip a bunch of redundant work in the case of hitting the depth limit. + c.instantiationCount = 5_000_000 return c.errorType } index := c.findActiveMapper(m) diff --git a/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt new file mode 100644 index 0000000000..3ffc0188f5 --- /dev/null +++ b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.errors.txt @@ -0,0 +1,21 @@ +recursiveConditionalCrash5.ts(13,6): error TS2589: Type instantiation is excessively deep and possibly infinite. + + +==== recursiveConditionalCrash5.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/63269 + + type Prepend = T extends unknown + ? ((arg: Elm, ...rest: T) => void) extends (...args: infer T2) => void + ? T2 + : never + : never; + + type ExactExtract = (T extends U ? U extends T ? T : never : never) & string; + + type Conv = { + 0: [T]; + 1: Prepend>>; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2589: Type instantiation is excessively deep and possibly infinite. + }[U extends T ? 0 : 1]; + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols new file mode 100644 index 0000000000..f069549903 --- /dev/null +++ b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.symbols @@ -0,0 +1,58 @@ +//// [tests/cases/compiler/recursiveConditionalCrash5.ts] //// + +=== recursiveConditionalCrash5.ts === +// https://github.com/microsoft/TypeScript/issues/63269 + +type Prepend = T extends unknown +>Prepend : Symbol(Prepend, Decl(recursiveConditionalCrash5.ts, 0, 0)) +>Elm : Symbol(Elm, Decl(recursiveConditionalCrash5.ts, 2, 13)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 2, 17)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 2, 17)) + + ? ((arg: Elm, ...rest: T) => void) extends (...args: infer T2) => void +>arg : Symbol(arg, Decl(recursiveConditionalCrash5.ts, 3, 6)) +>Elm : Symbol(Elm, Decl(recursiveConditionalCrash5.ts, 2, 13)) +>rest : Symbol(rest, Decl(recursiveConditionalCrash5.ts, 3, 15)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 2, 17)) +>args : Symbol(args, Decl(recursiveConditionalCrash5.ts, 3, 46)) +>T2 : Symbol(T2, Decl(recursiveConditionalCrash5.ts, 3, 60)) + + ? T2 +>T2 : Symbol(T2, Decl(recursiveConditionalCrash5.ts, 3, 60)) + + : never + : never; + +type ExactExtract = (T extends U ? U extends T ? T : never : never) & string; +>ExactExtract : Symbol(ExactExtract, Decl(recursiveConditionalCrash5.ts, 6, 10)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 8, 18)) +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 8, 20)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 8, 18)) +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 8, 20)) +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 8, 20)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 8, 18)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 8, 18)) + +type Conv = { +>Conv : Symbol(Conv, Decl(recursiveConditionalCrash5.ts, 8, 83)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 10, 12)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) + + 0: [T]; +>0 : Symbol(0, Decl(recursiveConditionalCrash5.ts, 10, 23)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) + + 1: Prepend>>; +>1 : Symbol(1, Decl(recursiveConditionalCrash5.ts, 11, 9)) +>Prepend : Symbol(Prepend, Decl(recursiveConditionalCrash5.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) +>Conv : Symbol(Conv, Decl(recursiveConditionalCrash5.ts, 8, 83)) +>ExactExtract : Symbol(ExactExtract, Decl(recursiveConditionalCrash5.ts, 6, 10)) +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 10, 12)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) + +}[U extends T ? 0 : 1]; +>U : Symbol(U, Decl(recursiveConditionalCrash5.ts, 10, 12)) +>T : Symbol(T, Decl(recursiveConditionalCrash5.ts, 10, 10)) + diff --git a/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types new file mode 100644 index 0000000000..7c34e4e493 --- /dev/null +++ b/testdata/baselines/reference/compiler/recursiveConditionalCrash5.types @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/recursiveConditionalCrash5.ts] //// + +=== recursiveConditionalCrash5.ts === +// https://github.com/microsoft/TypeScript/issues/63269 + +type Prepend = T extends unknown +>Prepend : Prepend + + ? ((arg: Elm, ...rest: T) => void) extends (...args: infer T2) => void +>arg : Elm +>rest : T +>args : T2 + + ? T2 + : never + : never; + +type ExactExtract = (T extends U ? U extends T ? T : never : never) & string; +>ExactExtract : ExactExtract + +type Conv = { +>Conv : Conv + + 0: [T]; +>0 : [T] + + 1: Prepend>>; +>1 : Prepend, ExactExtract>> + +}[U extends T ? 0 : 1]; + diff --git a/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts b/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts new file mode 100644 index 0000000000..2303058f23 --- /dev/null +++ b/testdata/tests/cases/compiler/recursiveConditionalCrash5.ts @@ -0,0 +1,17 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/63269 + +type Prepend = T extends unknown + ? ((arg: Elm, ...rest: T) => void) extends (...args: infer T2) => void + ? T2 + : never + : never; + +type ExactExtract = (T extends U ? U extends T ? T : never : never) & string; + +type Conv = { + 0: [T]; + 1: Prepend>>; +}[U extends T ? 0 : 1];