Skip to content

Fix stack overflow crash in base constraint resolution#4242

Merged
ahejlsberg merged 3 commits into
mainfrom
fix-ts-63269
Jun 12, 2026
Merged

Fix stack overflow crash in base constraint resolution#4242
ahejlsberg merged 3 commits into
mainfrom
fix-ts-63269

Conversation

@ahejlsberg

@ahejlsberg ahejlsberg commented Jun 8, 2026

Copy link
Copy Markdown
Member

This PR modifies base constraint resolution for conditional types to ensure the logic is protected by the recursion limiter in getResolvedBaseConstraint.

Fixes microsoft/TypeScript#63269.
Fixes microsoft/TypeScript#62966.

Copilot AI review requested due to automatic review settings June 8, 2026 16:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts base-constraint resolution for conditional types in the Go checker to avoid stack overflows by ensuring distributive-conditional base-constraint computation stays within the getResolvedBaseConstraint recursion limiter. It also adds a regression test and updates affected baselines.

Changes:

  • Update computeBaseConstraint to inline distributive-conditional constraint computation for TypeFlagsConditional.
  • Add a new compiler regression test infiniteConstraints2.ts.
  • Update submodule baseline diagnostics for infiniteConstraints.ts and add new baselines for infiniteConstraints2.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/checker/checker.go Changes conditional-type base constraint resolution to avoid unbounded recursion/stack overflow.
testdata/tests/cases/compiler/infiniteConstraints2.ts Adds a repro-style regression test for the conditional-type constraint recursion scenario.
testdata/baselines/reference/compiler/infiniteConstraints2.types New baseline for the added regression test.
testdata/baselines/reference/compiler/infiniteConstraints2.symbols New baseline for the added regression test.
testdata/baselines/reference/submodule/compiler/infiniteConstraints.errors.txt Updates expected diagnostics (now includes recursion limiter diagnostics instead of crashing).
testdata/baselines/reference/submodule/compiler/infiniteConstraints.errors.txt.diff Corresponding submodule baseline diff update.

Comment on lines +27386 to +27387
d := t.AsConditionalType()
if d.root.isDistributive && c.cachedTypes[CachedTypeKey{kind: CachedTypeKindRestrictiveInstantiation, typeId: t.id}] != t {

export type Prepend<Elm, T extends unknown[]> =
T extends unknown ?
((arg: Elm, ...rest: T) => void) extends ((...args: infer T2) => void) ? T2 :

type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2321: Excessive stack depth comparing types '"val"' and 'keyof Extract<B[Exclude<keyof B, K>], { val: string; }>'.

@ahejlsberg ahejlsberg Jun 8, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This excessive stack depth error occurs because we recursively build up a relation stack of 100 keyof XXX types, where XXX is an inifinitely recurring conditional type. We could silence this error (and instead produce a "maybe" result) by introducing distinct recursion identities for keyof types, but the error seems reasonable.

@RyanCavanaugh RyanCavanaugh added this to the Post-7.0 milestone Jun 8, 2026
@ahejlsberg

Copy link
Copy Markdown
Member Author

@typescript-bot test it

@typescript-automation

typescript-automation Bot commented Jun 12, 2026

Copy link
Copy Markdown

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
test top400 ✅ Started ✅ Results
perf test this faster ✅ Started 👀 Results

@typescript-automation

Copy link
Copy Markdown

@ahejlsberg
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - native
Errors 4 4 ~ ~ ~ p=1.000 n=6
Symbols 81,791 (± 0.02%) 81,786 (± 0.06%) ~ 81,715 81,842 p=1.000 n=6
Types 98,821 98,821 ~ ~ ~ p=1.000 n=6
Memory Used 180,175k (± 0.26%) 179,009k (± 0.69%) ~ 177,061k 180,425k p=0.128 n=6
Memory Allocs 1,564,803 (± 0.01%) 1,564,646 (± 0.02%) ~ 1,564,166 1,564,892 p=0.298 n=6
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Parse Time 0.065s (± 8.47%) 0.059s (± 9.34%) ~ 0.052s 0.068s p=0.092 n=6
Bind Time 0.018s (±22.92%) 0.018s (±16.46%) ~ 0.015s 0.023s p=1.000 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 0.854s (± 0.86%) 0.858s (± 2.04%) ~ 0.833s 0.875s p=0.378 n=6
Total Time 0.939s (± 1.58%) 0.937s (± 2.12%) ~ 0.909s 0.963s p=1.000 n=6
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=6
Symbols 885,094 (± 0.04%) 884,675 (± 0.08%) ~ 883,806 885,856 p=0.230 n=6
Types 263,972 (± 0.00%) 263,767 (± 0.00%) -205 (- 0.08%) 263,766 263,770 p=0.004 n=6
Memory Used 831,232k (± 0.10%) 830,727k (± 0.08%) ~ 830,131k 831,900k p=0.173 n=6
Memory Allocs 6,808,760 (± 0.24%) 6,818,620 (± 0.27%) ~ 6,797,777 6,839,578 p=0.575 n=6
Config Time 0.017s (± 2.38%) 0.017s (± 2.38%) ~ 0.017s 0.018s p=1.000 n=6
Parse Time 0.255s (± 2.81%) 0.253s (± 6.41%) ~ 0.229s 0.271s p=0.936 n=6
Bind Time 0.049s (±31.34%) 0.051s (±40.94%) ~ 0.034s 0.083s p=0.936 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 1.899s (± 0.80%) 1.879s (± 1.28%) ~ 1.857s 1.910s p=0.228 n=6
Total Time 2.235s (± 1.05%) 2.212s (± 1.07%) ~ 2.184s 2.241s p=0.149 n=6
mui-docs - native
Errors 11,242 (± 0.04%) 11,244 (± 0.02%) ~ 11,240 11,246 p=0.511 n=6
Symbols 4,186,698 4,212,918 +26,220 (+ 0.63%) ~ ~ p=0.001 n=6
Types 1,531,646 1,532,172 +526 (+ 0.03%) ~ ~ p=0.001 n=6
Memory Used 4,874,153k (± 0.05%) 4,963,426k (± 0.06%) +89,273k (+ 1.83%) 4,960,225k 4,968,391k p=0.005 n=6
Memory Allocs 79,969,052 (±17.24%) 71,409,049 (±16.14%) ~ 56,733,224 90,153,019 p=0.298 n=6
Config Time 0.017s (± 6.94%) 0.017s (± 7.42%) ~ 0.016s 0.019s p=0.389 n=6
Parse Time 0.992s (±19.46%) 0.889s (±18.39%) ~ 0.700s 1.144s p=0.378 n=6
Bind Time 0.002s 0.002s ~ ~ ~ p=1.000 n=6
Check Time 16.830s (± 0.53%) 17.010s (± 0.49%) +0.180s (+ 1.07%) 16.905s 17.110s p=0.013 n=6
Emit Time 0.440s (± 3.41%) 0.443s (± 3.42%) ~ 0.435s 0.474s p=0.226 n=6
Total Time 18.918s (± 1.22%) 18.986s (± 1.42%) ~ 18.681s 19.357s p=0.936 n=6
self-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,396,711 1,396,711 ~ ~ ~ p=1.000 n=6
Types 442,164 442,161 -3 (- 0.00%) ~ ~ p=0.001 n=6
Memory Used 1,646,420k (± 0.20%) 1,642,125k (± 0.47%) ~ 1,634,028k 1,653,499k p=0.298 n=6
Memory Allocs 54,845,041 (± 0.03%) 54,811,560 (± 0.14%) ~ 54,737,849 54,940,221 p=0.298 n=6
Config Time 0.013s (±32.96%) 0.010s (±74.22%) ~ 0.005s 0.024s p=0.199 n=6
Parse Time 0.276s (± 3.49%) 0.271s (± 4.08%) ~ 0.260s 0.285s p=0.378 n=6
Bind Time 0.000s 0.000s (±154.76%) ~ 0.000s 0.001s p=0.174 n=6
Check Time 2.351s (± 0.88%) 2.326s (± 1.08%) ~ 2.311s 2.376s p=0.065 n=6
Emit Time 0.226s (± 2.65%) 0.231s (± 5.80%) ~ 0.216s 0.253s p=0.470 n=6
Total Time 29.872s (± 0.61%) 29.675s (± 1.06%) ~ 29.171s 29.994s p=0.298 n=6
self-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 338,176 338,176 ~ ~ ~ p=1.000 n=6
Types 199,522 199,522 ~ ~ ~ p=1.000 n=6
Memory Used 332,077k (± 0.03%) 332,047k (± 0.03%) ~ 331,945k 332,230k p=0.575 n=6
Memory Allocs 2,368,983 (± 0.02%) 2,370,172 (± 0.05%) +1,190 (+ 0.05%) 2,368,743 2,372,446 p=0.045 n=6
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=6
Parse Time 0.128s (± 4.47%) 0.129s (± 2.98%) ~ 0.125s 0.136s p=0.747 n=6
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Check Time 1.384s (± 0.51%) 1.407s (± 1.33%) +0.024s (+ 1.70%) 1.387s 1.440s p=0.020 n=6
Emit Time 0.089s (± 6.88%) 0.084s (±11.10%) ~ 0.076s 0.101s p=0.261 n=6
Total Time 1.655s (± 0.88%) 1.673s (± 0.88%) ~ 1.660s 1.699s p=0.109 n=6
ts-pre-modules - native
Errors 3 3 ~ ~ ~ p=1.000 n=6
Symbols 97,488 97,488 ~ ~ ~ p=1.000 n=6
Types 356 356 ~ ~ ~ p=1.000 n=6
Memory Used 133,414k (± 0.03%) 133,395k (± 0.01%) ~ 133,364k 133,415k p=0.298 n=6
Memory Allocs 182,912 (± 0.08%) 182,625 (± 0.15%) ~ 182,398 183,138 p=0.066 n=6
Config Time 0.001s (±48.94%) 0.001s (±48.94%) ~ 0.000s 0.001s p=1.000 n=6
Parse Time 0.114s (± 4.29%) 0.114s (± 3.93%) ~ 0.107s 0.118s p=1.000 n=6
Bind Time 0.043s (± 4.84%) 0.037s (±16.34%) ~ 0.029s 0.045s p=0.091 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Total Time 0.160s (± 3.55%) 0.154s (± 3.96%) ~ 0.147s 0.162s p=0.170 n=6
vscode - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 6,635,454 6,635,454 ~ ~ ~ p=1.000 n=6
Types 2,331,878 2,331,859 -19 (- 0.00%) ~ ~ p=0.001 n=6
Memory Used 4,486,100k (± 0.02%) 4,485,554k (± 0.02%) ~ 4,484,823k 4,486,848k p=0.298 n=6
Memory Allocs 31,585,247 (± 0.04%) 31,593,261 (± 0.04%) ~ 31,577,761 31,613,962 p=0.230 n=6
Config Time 0.068s (± 8.10%) 0.068s (±10.04%) ~ 0.061s 0.079s p=0.748 n=6
Parse Time 0.884s (± 1.93%) 0.876s (± 3.25%) ~ 0.835s 0.906s p=0.471 n=6
Bind Time 0.133s (± 2.20%) 0.157s (±21.98%) ~ 0.128s 0.217s p=0.567 n=6
Check Time 8.737s (± 1.09%) 8.781s (± 0.93%) ~ 8.669s 8.866s p=0.378 n=6
Emit Time 2.177s (± 8.20%) 2.119s (±10.66%) ~ 1.886s 2.449s p=0.810 n=6
Total Time 12.014s (± 0.90%) 12.026s (± 1.24%) ~ 11.919s 12.295s p=0.810 n=6
webpack - native
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 181,636 181,636 ~ ~ ~ p=1.000 n=6
Types 340 340 ~ ~ ~ p=1.000 n=6
Memory Used 219,185k (± 0.19%) 219,336k (± 0.03%) ~ 219,254k 219,419k p=0.378 n=6
Memory Allocs 1,062,464 (± 1.08%) 1,073,884 (± 1.62%) ~ 1,058,839 1,103,149 p=0.230 n=6
Config Time 0.009s (±20.00%) 0.010s (±11.88%) ~ 0.008s 0.011s p=0.621 n=6
Parse Time 0.143s (± 3.63%) 0.149s (± 5.04%) ~ 0.140s 0.159s p=0.090 n=6
Bind Time 0s 0s ~ ~ ~ p=1.000 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 0.048s (±19.58%) 0.044s (±21.73%) ~ 0.033s 0.060s p=0.521 n=6
Total Time 0.200s (± 3.83%) 0.203s (± 2.99%) ~ 0.199s 0.211s p=0.808 n=6
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,060,815 1,060,884 +69 (+ 0.01%) ~ ~ p=0.001 n=6
Types 384,533 382,962 -1,571 (- 0.41%) ~ ~ p=0.001 n=6
Memory Used 638,767k (± 0.01%) 638,505k (± 0.01%) -262k (- 0.04%) 638,390k 638,568k p=0.005 n=6
Memory Allocs 5,019,589 (± 0.03%) 5,003,094 (± 0.07%) -16,495 (- 0.33%) 4,997,700 5,006,494 p=0.005 n=6
Config Time 0.005s (±11.05%) 0.005s (±11.05%) ~ 0.004s 0.005s p=1.000 n=6
Parse Time 0.133s (± 1.41%) 0.131s (± 5.11%) ~ 0.123s 0.141s p=0.748 n=6
Bind Time 0.028s (±14.02%) 0.034s (±24.15%) ~ 0.024s 0.044s p=0.226 n=6
Check Time 1.286s (± 0.32%) 1.277s (± 1.11%) ~ 1.259s 1.297s p=0.295 n=6
Emit Time 0.001s 0.001s ~ ~ ~ p=1.000 n=6
Total Time 1.456s (± 0.54%) 1.451s (± 1.03%) ~ 1.435s 1.477s p=0.471 n=6
System info unknown
Hosts
  • native
Scenarios
  • Compiler-Unions - native
  • angular-1 - native
  • mui-docs - native
  • self-build-src - native
  • self-compiler - native
  • ts-pre-modules - native
  • vscode - native
  • webpack - native
  • xstate-main - native
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@typescript-automation

Copy link
Copy Markdown

@ahejlsberg Here are the results of running the top 400 repos with tsc comparing main and refs/pull/4242/merge:

Everything looks good!

@jakebailey jakebailey left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like a comment would be worth it, but not blocking I suppose

@ahejlsberg ahejlsberg added this pull request to the merge queue Jun 12, 2026
@ahejlsberg

Copy link
Copy Markdown
Member Author

I feel like a comment would be worth it, but not blocking I suppose

The whole purpose of getResolvedBaseConstraint is to resolve base constraints with an infinite recursion limiter, so I don't think a comment would add anything new.

Merged via the queue into main with commit 4cf361f Jun 12, 2026
22 checks passed
@ahejlsberg ahejlsberg deleted the fix-ts-63269 branch June 12, 2026 18:36
christianvuerings added a commit to christianvuerings/typescript-go that referenced this pull request Jun 12, 2026
* origin/main:
  Make LS checkers time out after being idle, segment based on use (take 2) (microsoft#3435)
  Fix external helper crash after module-status updates (microsoft#3994)
  Allow LSP server to use builtin watcher on Windows and macOS (microsoft#4288)
  Rebuilt CLI watcher around new `fswatch` package (microsoft#4026)
  Fix stack overflow crash in base constraint resolution (microsoft#4242)

# Conflicts:
#	internal/project/session.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants