Visitar URL original
Bound recursive array and tuple type printing by Copilot · Pull Request #64694 · microsoft/TypeScript · GitHub
Skip to content

Bound recursive array and tuple type printing - #64694

Draft
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-recursive-type-printer
Draft

Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-recursive-type-printer

Conversation

Copilot AI commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Recursive generic types can produce a fresh array or tuple at every level, evading the type printer’s exact-cycle check. Printing them can overflow the stack or affect later type checking.

  • Change: Bound active array/tuple serialization depth independently of exact-cycle detection.
  • Coverage: Add regressions for noErrorTruncation diagnostics, declaration emit, and a subsequent diagnostic.

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix type printer recursion issue with nested array/tuple types Bound recursive array and tuple type printing Oct 8, 2026
@jakebailey

Copy link
Copy Markdown
Member

I think this is probably fine; hopefully interacts fine with #64662 eventually.

TypeScript Bot (@typescript-bot) test it

@typescript-automation

typescript-automation Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

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

Command Status Results
test top400 ✅ Started ✅ Results
user test this ✅ Started ✅ Results
run dt ✅ Started ✅ Results
perf test this faster ✅ Started 👀 Results

@jakebailey

Copy link
Copy Markdown
Member

I had my review session for #64662 look at this and it said:


The core approach looks sound as a focused crash fix: active container depth is independent of exact-cycle detection, the bound still applies with noErrorTruncation, and declaration emit uses the existing truncation diagnostic rather than silently emitting a successful declaration containing synthesized any.

Two coverage concerns before treating all of #64683 as resolved:

  1. The later diagnostic does not exercise the reported cache poisoning. later: number = "oops" would still error if generic declarations first resolved during printing had become cached errors. A reduced regression should first print the problematic type, then instantiate a shared generic declaration and verify that the result has not become any. The reported API ordering, printing before querying another type, is also worth covering. This need not introduce an arktype dependency.

  2. Cover the finite-depth boundary. The counter limits legitimate finite array/tuple nesting as well as runaway expansion. Tests below, at, and above the depth of 20, including tuple-focused cases, would make the intended behavior explicit and protect the boundary.

These are coverage gaps, not demonstrated failures of the proposed implementation.

@typescript-automation

Copy link
Copy Markdown
Contributor

Hey Jake Bailey (@jakebailey), the results of running the DT tests are ready.

Everything looks the same!

You can check the log here.

@typescript-automation

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey) Here are the results of running the user tests with tsc comparing baseline and pr:

Everything looks good!

@typescript-automation

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey)
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 41 41 ~ ~ ~ p=1.000 n=12
Symbols 115,276 115,276 ~ ~ ~ p=1.000 n=12
Types 79,613 79,613 ~ ~ ~ p=1.000 n=12
Memory Used 135,322k (± 0.07%) 135,267k (± 0.06%) ~ 135,033k 135,468k p=0.319 n=12
Memory Allocs 2,190,659 (± 0.01%) 2,190,672 (± 0.00%) ~ 2,190,456 2,190,926 p=0.945 n=12
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Parse Time 0.040s (± 4.41%) 0.040s (± 3.75%) ~ 0.037s 0.045s p=0.876 n=12
Bind Time 0.012s (±10.52%) 0.013s (±16.69%) ~ 0.010s 0.019s p=0.887 n=12
Check Time 0.493s (± 1.13%) 0.495s (± 0.74%) ~ 0.487s 0.507s p=0.560 n=12
Emit Time 0.264s (± 2.53%) 0.266s (± 2.07%) ~ 0.246s 0.276s p=0.523 n=12
Total Time 0.816s (± 0.86%) 0.819s (± 0.88%) ~ 0.796s 0.839s p=0.433 n=12
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=12
Symbols 845,606 (± 0.06%) 845,519 (± 0.05%) ~ 844,525 847,396 p=0.410 n=12
Types 248,126 (± 0.00%) 248,125 (± 0.00%) ~ 248,122 248,135 p=0.398 n=12
Memory Used 764,631k (± 0.02%) 764,604k (± 0.02%) ~ 764,337k 764,908k p=0.755 n=12
Memory Allocs 12,918,495 (± 0.02%) 12,925,265 (± 0.09%) ~ 12,915,253 12,984,963 p=0.443 n=12
Config Time 0.017s 0.017s ~ ~ ~ p=1.000 n=12
Parse Time 0.257s (± 2.12%) 0.260s (± 1.92%) ~ 0.248s 0.275s p=0.486 n=12
Bind Time 0.059s (± 3.45%) 0.058s (± 1.05%) ~ 0.056s 0.059s p=0.131 n=12
Check Time 0s 0s ~ ~ ~ p=1.000 n=12
Emit Time 1.578s (± 1.20%) 1.558s (± 0.61%) ~ 1.529s 1.585s p=0.057 n=12
Total Time 1.926s (± 1.18%) 1.904s (± 0.46%) ~ 1.878s 1.922s p=0.103 n=12
mui-docs - native
Errors 11,405 11,405 ~ ~ ~ p=1.000 n=12
Symbols 4,359,614 4,359,614 ~ ~ ~ p=1.000 n=12
Types 1,376,379 1,376,379 ~ ~ ~ p=1.000 n=12
Memory Used 2,872,095k (± 0.05%) 2,873,954k (± 0.05%) ~ 2,871,732k 2,877,943k p=0.128 n=12
Memory Allocs 32,824,912 (± 0.05%) 32,849,034 (± 0.04%) +24,122 (+ 0.07%) 32,810,508 32,887,290 p=0.033 n=12
Config Time 0.017s 0.017s (± 1.07%) ~ 0.016s 0.017s p=1.000 n=12
Parse Time 0.500s (± 3.31%) 0.492s (± 3.31%) ~ 0.456s 0.531s p=0.522 n=12
Bind Time 0.002s 0.002s ~ ~ ~ p=1.000 n=12
Check Time 8.652s (± 0.55%) 8.647s (± 0.58%) ~ 8.542s 8.780s p=0.989 n=12
Emit Time 0.465s (±12.25%) 0.504s (±13.70%) ~ 0.419s 0.671s p=0.541 n=12
Total Time 10.399s (± 0.47%) 10.428s (± 0.50%) ~ 10.271s 10.517s p=0.325 n=12
strada-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,390,229 1,390,229 ~ ~ ~ p=1.000 n=12
Types 441,498 441,498 ~ ~ ~ p=1.000 n=12
Memory Used 1,650,435k (± 1.09%) 1,642,603k (± 0.73%) ~ 1,627,168k 1,681,566k p=0.799 n=12
Memory Allocs 92,190,711 (± 0.19%) 92,138,149 (± 0.17%) ~ 91,759,635 92,469,796 p=0.443 n=12
Config Time 0.004s (± 9.04%) 0.003s (± 9.29%) ~ 0.003s 0.004s p=0.414 n=12
Parse Time 0.199s (± 3.82%) 0.195s (± 5.73%) ~ 0.169s 0.227s p=0.434 n=12
Bind Time 0.000s 0.000s (±217.90%) ~ 0.000s 0.001s p=1.000 n=12
Check Time 1.789s (± 0.83%) 1.798s (± 0.75%) ~ 1.750s 1.824s p=0.259 n=12
Emit Time 0.292s (± 4.83%) 0.299s (± 4.84%) ~ 0.261s 0.333s p=0.487 n=12
Total Time 23.223s (± 0.55%) 23.387s (± 0.87%) ~ 22.974s 23.770s p=0.259 n=12
strada-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 334,953 334,953 ~ ~ ~ p=1.000 n=12
Types 197,616 197,616 ~ ~ ~ p=1.000 n=12
Memory Used 302,645k (± 0.03%) 302,662k (± 0.04%) ~ 302,278k 302,897k p=0.551 n=12
Memory Allocs 4,623,124 (± 0.01%) 4,623,144 (± 0.01%) ~ 4,622,013 4,624,189 p=0.843 n=12
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=12
Parse Time 0.111s (± 4.82%) 0.119s (± 4.13%) 🔻+0.008s (+ 7.50%) 0.100s 0.132s p=0.011 n=12
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Check Time 1.037s (± 0.60%) 1.042s (± 0.50%) ~ 1.027s 1.055s p=0.138 n=12
Emit Time 0.132s (±10.54%) 0.130s (±12.03%) ~ 0.096s 0.167s p=0.766 n=12
Total Time 1.335s (± 1.14%) 1.345s (± 0.95%) ~ 1.305s 1.375s p=0.272 n=12
ts-pre-modules - native
Errors 87 87 ~ ~ ~ p=1.000 n=12
Symbols 303,834 303,834 ~ ~ ~ p=1.000 n=12
Types 181,663 181,663 ~ ~ ~ p=1.000 n=12
Memory Used 263,552k (± 0.02%) 263,546k (± 0.02%) ~ 263,413k 263,667k p=0.855 n=12
Memory Allocs 1,615,955 (± 0.01%) 1,616,035 (± 0.01%) ~ 1,615,526 1,616,546 p=0.541 n=12
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Parse Time 0.098s (± 3.65%) 0.099s (± 4.64%) ~ 0.089s 0.114s p=0.897 n=12
Bind Time 0.038s (±11.44%) 0.037s (±12.49%) ~ 0.028s 0.050s p=0.488 n=12
Check Time 0.813s (± 0.70%) 0.816s (± 0.65%) ~ 0.801s 0.831s p=0.560 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 0.963s (± 0.69%) 0.966s (± 0.83%) ~ 0.946s 0.991s p=0.468 n=12
vscode - native
Errors 395 395 ~ ~ ~ p=1.000 n=12
Symbols 11,242,258 11,242,258 ~ ~ ~ p=1.000 n=12
Types 3,727,089 3,727,089 ~ ~ ~ p=1.000 n=12
Memory Used 6,766,065k (± 0.01%) 6,768,299k (± 0.01%) +2,234k (+ 0.03%) 6,766,423k 6,771,530k p=0.003 n=12
Memory Allocs 55,296,678 (± 0.01%) 55,299,061 (± 0.01%) ~ 55,286,823 55,328,584 p=0.291 n=12
Config Time 0.075s (± 0.33%) 0.075s (± 0.54%) ~ 0.075s 0.077s p=0.068 n=12
Parse Time 1.792s (± 3.59%) 1.930s (± 3.10%) 🔻+0.138s (+ 7.71%) 1.723s 2.010s p=0.001 n=12
Bind Time 0.657s (±20.60%) 0.516s (±17.44%) ~ 0.444s 0.854s p=0.057 n=12
Check Time 14.522s (± 1.17%) 14.714s (± 0.86%) ~ 14.275s 14.876s p=0.128 n=12
Emit Time 5.311s (±10.60%) 4.503s (± 9.34%) ~ 4.153s 5.935s p=0.160 n=12
Total Time 22.449s (± 2.11%) 21.821s (± 1.55%) ~ 21.478s 22.965s p=0.291 n=12
webpack - native
Errors 584 584 ~ ~ ~ p=1.000 n=12
Symbols 1,306,646 1,306,646 ~ ~ ~ p=1.000 n=12
Types 618,489 618,489 ~ ~ ~ p=1.000 n=12
Memory Used 967,073k (± 0.01%) 967,225k (± 0.02%) ~ 966,855k 967,801k p=0.410 n=12
Memory Allocs 6,628,196 (± 0.02%) 6,627,910 (± 0.01%) ~ 6,625,627 6,631,080 p=0.755 n=12
Config Time 0.009s 0.009s ~ ~ ~ p=1.000 n=12
Parse Time 0.285s (± 2.84%) 0.295s (± 3.03%) ~ 0.268s 0.312s p=0.066 n=12
Bind Time 0.084s (±16.35%) 0.077s (±15.70%) ~ 0.063s 0.111s p=0.269 n=12
Check Time 1.969s (± 0.49%) 1.989s (± 0.53%) +0.020s (+ 1.03%) 1.955s 2.018s p=0.008 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 2.384s (± 0.37%) 2.406s (± 0.51%) +0.021s (+ 0.89%) 2.375s 2.436s p=0.007 n=12
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,055,452 1,055,452 ~ ~ ~ p=1.000 n=12
Types 386,738 386,738 ~ ~ ~ p=1.000 n=12
Memory Used 570,799k (± 0.02%) 570,840k (± 0.03%) ~ 570,413k 571,349k p=0.590 n=12
Memory Allocs 4,860,253 (± 0.08%) 4,862,127 (± 0.05%) ~ 4,855,995 4,867,088 p=0.319 n=12
Config Time 0.003s 0.003s ~ ~ ~ p=1.000 n=12
Parse Time 0.145s (± 2.60%) 0.140s (± 4.62%) ~ 0.129s 0.158s p=0.162 n=12
Bind Time 0.048s (±18.00%) 0.051s (±18.24%) ~ 0.033s 0.070s p=0.614 n=12
Check Time 1.119s (± 0.40%) 1.122s (± 0.49%) ~ 1.112s 1.142s p=0.485 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 1.324s (± 0.73%) 1.325s (± 0.48%) ~ 1.310s 1.345s p=0.899 n=12
System info unknown
Hosts
  • native
Scenarios
  • Compiler-Unions - native
  • angular-1 - native
  • mui-docs - native
  • strada-build-src - native
  • strada-compiler - native
  • ts-pre-modules - native
  • vscode - native
  • webpack - native
  • xstate-main - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

Developer Information:

Download Benchmarks

@typescript-automation

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey) Here are the results of running the top 400 repos with tsc comparing baseline and pr:

Everything looks good!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type printer recurses without limit into nested array/tuple types (stack overflow; can leave later types any)

3 participants