From 2bc8933ca14125ce7a6a761cf14824d4963af742 Mon Sep 17 00:00:00 2001 From: moznion Date: Fri, 21 Nov 2025 12:52:23 +0900 Subject: [PATCH 1/2] Add reproduction test case for #61524 Signed-off-by: moznion --- .../issue61524DebugFailureCrash.errors.txt | 28 ++++++ .../issue61524DebugFailureCrash.symbols | 61 +++++++++++++ .../issue61524DebugFailureCrash.types | 89 +++++++++++++++++++ .../compiler/issue61524DebugFailureCrash.ts | 22 +++++ 4 files changed, 200 insertions(+) create mode 100644 tests/baselines/reference/issue61524DebugFailureCrash.errors.txt create mode 100644 tests/baselines/reference/issue61524DebugFailureCrash.symbols create mode 100644 tests/baselines/reference/issue61524DebugFailureCrash.types create mode 100644 tests/cases/compiler/issue61524DebugFailureCrash.ts diff --git a/tests/baselines/reference/issue61524DebugFailureCrash.errors.txt b/tests/baselines/reference/issue61524DebugFailureCrash.errors.txt new file mode 100644 index 0000000000000..28fa911c954e2 --- /dev/null +++ b/tests/baselines/reference/issue61524DebugFailureCrash.errors.txt @@ -0,0 +1,28 @@ +issue61524DebugFailureCrash.ts(10,37): error TS2550: Property 'entries' does not exist on type 'ObjectConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2017' or later. +issue61524DebugFailureCrash.ts(11,9): error TS2769: No overload matches this call. + + +==== issue61524DebugFailureCrash.ts (2 errors) ==== + // Exact reproduction from https://github.com/microsoft/TypeScript/issues/61524 + // This code causes "Debug Failure. No error for last overload signature" + + type Generic = T extends any[] ? T[number] : T[keyof T]; + + export function testFn>( + obj: A, + cb: (b: Generic>) => any + ) { + for (const [key, val] of Object.entries(obj)) { + ~~~~~~~ +!!! error TS2550: Property 'entries' does not exist on type 'ObjectConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2017' or later. + cb(val as Generic); + ~~ +!!! error TS2769: No overload matches this call. + } + } + + // Usage that triggers the crash + testFn( + { foo: "bar", num: 42 }, + (val) => console.log(val) // Type inference here causes the issue + ); \ No newline at end of file diff --git a/tests/baselines/reference/issue61524DebugFailureCrash.symbols b/tests/baselines/reference/issue61524DebugFailureCrash.symbols new file mode 100644 index 0000000000000..58a0ccdd7ba95 --- /dev/null +++ b/tests/baselines/reference/issue61524DebugFailureCrash.symbols @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/issue61524DebugFailureCrash.ts] //// + +=== issue61524DebugFailureCrash.ts === +// Exact reproduction from https://github.com/microsoft/TypeScript/issues/61524 +// This code causes "Debug Failure. No error for last overload signature" + +type Generic = T extends any[] ? T[number] : T[keyof T]; +>Generic : Symbol(Generic, Decl(issue61524DebugFailureCrash.ts, 0, 0)) +>T : Symbol(T, Decl(issue61524DebugFailureCrash.ts, 3, 13)) +>T : Symbol(T, Decl(issue61524DebugFailureCrash.ts, 3, 13)) +>T : Symbol(T, Decl(issue61524DebugFailureCrash.ts, 3, 13)) +>T : Symbol(T, Decl(issue61524DebugFailureCrash.ts, 3, 13)) +>T : Symbol(T, Decl(issue61524DebugFailureCrash.ts, 3, 13)) + +export function testFn>( +>testFn : Symbol(testFn, Decl(issue61524DebugFailureCrash.ts, 3, 59)) +>A : Symbol(A, Decl(issue61524DebugFailureCrash.ts, 5, 23)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + obj: A, +>obj : Symbol(obj, Decl(issue61524DebugFailureCrash.ts, 5, 54)) +>A : Symbol(A, Decl(issue61524DebugFailureCrash.ts, 5, 23)) + + cb: (b: Generic>) => any +>cb : Symbol(cb, Decl(issue61524DebugFailureCrash.ts, 6, 11)) +>b : Symbol(b, Decl(issue61524DebugFailureCrash.ts, 7, 9)) +>Generic : Symbol(Generic, Decl(issue61524DebugFailureCrash.ts, 0, 0)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(issue61524DebugFailureCrash.ts, 5, 23)) + +) { + for (const [key, val] of Object.entries(obj)) { +>key : Symbol(key, Decl(issue61524DebugFailureCrash.ts, 9, 16)) +>val : Symbol(val, Decl(issue61524DebugFailureCrash.ts, 9, 20)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>obj : Symbol(obj, Decl(issue61524DebugFailureCrash.ts, 5, 54)) + + cb(val as Generic); +>cb : Symbol(cb, Decl(issue61524DebugFailureCrash.ts, 6, 11)) +>val : Symbol(val, Decl(issue61524DebugFailureCrash.ts, 9, 20)) +>Generic : Symbol(Generic, Decl(issue61524DebugFailureCrash.ts, 0, 0)) +>A : Symbol(A, Decl(issue61524DebugFailureCrash.ts, 5, 23)) + } +} + +// Usage that triggers the crash +testFn( +>testFn : Symbol(testFn, Decl(issue61524DebugFailureCrash.ts, 3, 59)) + + { foo: "bar", num: 42 }, +>foo : Symbol(foo, Decl(issue61524DebugFailureCrash.ts, 16, 5)) +>num : Symbol(num, Decl(issue61524DebugFailureCrash.ts, 16, 17)) + + (val) => console.log(val) // Type inference here causes the issue +>val : Symbol(val, Decl(issue61524DebugFailureCrash.ts, 17, 5)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>val : Symbol(val, Decl(issue61524DebugFailureCrash.ts, 17, 5)) + +); diff --git a/tests/baselines/reference/issue61524DebugFailureCrash.types b/tests/baselines/reference/issue61524DebugFailureCrash.types new file mode 100644 index 0000000000000..36312fb89e10f --- /dev/null +++ b/tests/baselines/reference/issue61524DebugFailureCrash.types @@ -0,0 +1,89 @@ +//// [tests/cases/compiler/issue61524DebugFailureCrash.ts] //// + +=== issue61524DebugFailureCrash.ts === +// Exact reproduction from https://github.com/microsoft/TypeScript/issues/61524 +// This code causes "Debug Failure. No error for last overload signature" + +type Generic = T extends any[] ? T[number] : T[keyof T]; +>Generic : Generic +> : ^^^^^^^^^^ + +export function testFn>( +>testFn : >(obj: A, cb: (b: Generic>) => any) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + obj: A, +>obj : A +> : ^ + + cb: (b: Generic>) => any +>cb : (b: Generic>) => any +> : ^ ^^ ^^^^^ +>b : Generic> +> : ^^^^^^^^^^^^^^^^^^^ + +) { + for (const [key, val] of Object.entries(obj)) { +>key : any +> : ^^^ +>val : any +> : ^^^ +>Object.entries(obj) : any +> : ^^^ +>Object.entries : any +> : ^^^ +>Object : ObjectConstructor +> : ^^^^^^^^^^^^^^^^^ +>entries : any +> : ^^^ +>obj : A +> : ^ + + cb(val as Generic); +>cb(val as Generic) : any +> : ^^^ +>cb : (b: Generic>) => any +> : ^ ^^ ^^^^^ +>val as Generic : Generic +> : ^^^^^^^^^^ +>val : any +> : ^^^ + } +} + +// Usage that triggers the crash +testFn( +>testFn( { foo: "bar", num: 42 }, (val) => console.log(val) // Type inference here causes the issue) : void +> : ^^^^ +>testFn : >(obj: A, cb: (b: Generic>) => any) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + { foo: "bar", num: 42 }, +>{ foo: "bar", num: 42 } : { foo: string; num: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>foo : string +> : ^^^^^^ +>"bar" : "bar" +> : ^^^^^ +>num : number +> : ^^^^^^ +>42 : 42 +> : ^^ + + (val) => console.log(val) // Type inference here causes the issue +>(val) => console.log(val) : (val: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>val : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>console.log(val) : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>val : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +); diff --git a/tests/cases/compiler/issue61524DebugFailureCrash.ts b/tests/cases/compiler/issue61524DebugFailureCrash.ts new file mode 100644 index 0000000000000..4249ec0fe543d --- /dev/null +++ b/tests/cases/compiler/issue61524DebugFailureCrash.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noEmit: true + +// Exact reproduction from https://github.com/microsoft/TypeScript/issues/61524 +// This code causes "Debug Failure. No error for last overload signature" + +type Generic = T extends any[] ? T[number] : T[keyof T]; + +export function testFn>( + obj: A, + cb: (b: Generic>) => any +) { + for (const [key, val] of Object.entries(obj)) { + cb(val as Generic); + } +} + +// Usage that triggers the crash +testFn( + { foo: "bar", num: 42 }, + (val) => console.log(val) // Type inference here causes the issue +); \ No newline at end of file From 56578c522dc6295b5fe16f816312d1ef67bf8d5b Mon Sep 17 00:00:00 2001 From: moznion Date: Thu, 20 Nov 2025 16:41:40 +0900 Subject: [PATCH 2/2] Fix compiler crash on generics overload resolution failure reported by #61524 Replace `Debug.fail()` calls with proper error generation to prevent TypeScript compiler crashes when overload resolution fails for complex generic constraints, for example JSX elements. Problem -- The TypeScript compiler crashes with "Debug Failure. No error for last overload signature" when resolving certain complex generic constraints, e.g., JSX element types. This regression has existed since TypeScript 3.6 and affects many React/JSX projects. Root Cause -- When `getSignatureApplicabilityError()` returns no diagnostics for overload candidates, the compiler calls `Debug.fail()` instead of handling the edge case gracefully, causing an immediate crash. Solution -- - Replace `Debug.fail()` calls with fallback diagnostic generation - Generate appropriate error messages for unhandled overload resolution cases - Ensure compiler continues execution without crashing Related to #61524, #60229, #48636, #33133 Signed-off-by: moznion --- src/compiler/checker.ts | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8e5c03560db3e..7ff5cb1cd5a05 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -36603,7 +36603,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - Debug.fail("No error for last overload signature"); + // Fallback: Generate a generic error when no specific error can be determined + // This replaces the Debug.fail() to prevent compiler crashes + // See: https://github.com/microsoft/TypeScript/issues/61524 + const fallbackChain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.No_overload_matches_this_call, + ); + const errorNode = getErrorNodeForCallNode(node); + const fallbackDiag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode), + errorNode, + fallbackChain, + /*relatedInformation*/ undefined, + ); + + diagnostics.add(fallbackDiag); } } else { @@ -36624,7 +36639,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { allDiagnostics.push(diags); } else { - Debug.fail("No error for 3 or fewer overload signatures"); + // Fallback: Generate a generic error for this overload candidate + // This prevents crashes when processing multiple overload signatures + const fallbackChain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Overload_0_of_1_2_gave_the_following_error, + i + 1, + candidates.length, + signatureToString(c), + ); + const errorNode = getErrorNodeForCallNode(node); + const fallbackDiag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode), + errorNode, + fallbackChain, + /*relatedInformation*/ undefined, + ); + allDiagnostics.push([fallbackDiag]); } i++; }