Skip to content

fix: prevent stack overflow in symbolToTypeNode with recursive return type references#63322

Closed
wdskuki wants to merge 2 commits intomicrosoft:mainfrom
wdskuki:fix/recursive-return-type-crash-63273
Closed

fix: prevent stack overflow in symbolToTypeNode with recursive return type references#63322
wdskuki wants to merge 2 commits intomicrosoft:mainfrom
wdskuki:fix/recursive-return-type-crash-63273

Conversation

@wdskuki
Copy link
Copy Markdown

@wdskuki wdskuki commented Mar 30, 2026

Fixes #63273

Problem

When processing a type like:

function clone(): <T>(obj: T) => T extends any ? ReturnType<typeof clone>[0] : 0;

The compiler enters infinite recursion:

  1. typeToTypeNodeHelper processes the conditional type
  2. Calls symbolToTypeNode(clone, Value) to get typeof clone
  3. Which calls createAccessFromSymbolChaingetNameOfSymbolAsWritten(clone)
  4. Which tries to get the declaration name, triggering step 1 again
  5. Stack overflow

Solution

Add recursive reference detection in symbolToTypeNode using a visitedSymbols set in the NodeBuilderContext. When a symbol is detected as already being processed, return never type to break the cycle.

Changes

  • Added visitedSymbols: Set<string> | undefined to NodeBuilderContext interface
  • Added cycle detection at the start of symbolToTypeNode
  • Clean up visitedSymbols on all return paths

Testing

Test case from #63273:

function clone(): <T>(obj: T) => T extends any ? ReturnType<typeof clone>[0] : 0;

Before: RangeError: Maximum call stack size exceeded
After: Compiles successfully (returns never for the recursive reference)

Related Issues

These may benefit from similar protection or may need separate fixes.

wdsmini and others added 2 commits March 26, 2026 22:52
The error message 'Jump target cannot cross function boundary' was confusing
because it didn't indicate which label was causing the issue. This change
adds the label name to the error message when available.

Before: 'Jump target cannot cross function boundary.'
After:  'Jump target 'loopend' cannot cross function boundary.'

Fixes microsoft#30408
… type references

Fixes microsoft#63273

Add recursive reference detection in symbolToTypeNode using a visitedSymbols
set in NodeBuilderContext. When a symbol is detected as already being
processed, return never type to break the cycle.

This prevents compiler crashes when a function's return type references
itself via ReturnType<typeof functionName>.
@wdskuki
Copy link
Copy Markdown
Author

wdskuki commented Mar 30, 2026

@microsoft-github-policy-service agree

@RyanCavanaugh
Copy link
Copy Markdown
Member

See https://github.com/microsoft/TypeScript?tab=readme-ov-file#contribute - bugfixes should be in typescript-go repo

@github-project-automation github-project-automation bot moved this from Not started to Done in PR Backlog Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Crash: RangeError: Maximum call stack size exceeded in getNameOfSymbolAsWritten via recursive conditional ReturnType

2 participants