Skip to content

Fix deprecated contextual property memory regression - #4825

Open
Jake Bailey (jakebailey) wants to merge 7 commits into
mainfrom
jabaile/fix-4824
Open

Fix deprecated contextual property memory regression#4825
Jake Bailey (jakebailey) wants to merge 7 commits into
mainfrom
jabaile/fix-4824

Conversation

@jakebailey

Copy link
Copy Markdown
Member

Fixes #4824

A bit nasty to prevent memory balooning from deferring stuff, plus code to quickly discard duplicate diags for deprecations.

Copilot AI review requested due to automatic review settings August 3, 2026 22:43

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

Defers contextual deprecation checks until suggestion diagnostics to prevent speculative overload checks from ballooning memory.

Changes:

  • Tracks contextual object/JSX nodes for deferred checking.
  • Deduplicates deprecation suggestions by location and code.
  • Adds regression coverage for overloaded contextual properties.

Reviewed changes

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

File Description
internal/checker/checker.go Implements deferred checks and diagnostic deduplication.
internal/checker/jsx.go Registers JSX attributes for deferred checks.
internal/checker/types.go Adds per-source-file deferred-check state.
internal/fourslash/tests/deprecatedContextualPropertyOverload_test.go Verifies deprecation diagnostics with overloads.

Comment thread internal/checker/checker.go Outdated
Comment thread internal/checker/checker.go Outdated
@walkerdb

Walker Boyle (walkerdb) commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

tried this branch against the same large private repo that replicated in #4824 -- seems to fix the ram regression entirely, seeing about the same ram use as baseline on main.

@weswigham

Wesley Wigham (weswigham) commented Aug 4, 2026

Copy link
Copy Markdown
Member

Can't we avoid a new deferred check mechanism here by just reusing checkNodeDeferred - we already went through the effort of getting that working with span-based diags once. We should just be able to add c.checkNodeDeferred(node) to checkObjectLiteral and checkJsxAttributes, and then implementations in checkDeferredNode that boil down to just

contextualType := c.getApparentTypeOfContextualType(node, ContextFlagsNone)
for _, property := range node.Properties() {
	if property.Name() != nil && !ast.IsComputedPropertyName(property.Name()) {
		c.checkDeprecatedProperty(property.Name(), contextualType)
	}
}

(which would also fix some stuff in this PR RE non-identifier props it happens to break and make the contextual type lookup consistent between JSX and object literals (it should always be apparent since looking for members inside checkDeprecatedProperty will get apparent members anyway))

@jakebailey

Copy link
Copy Markdown
Member Author

That does work, though does use a bit more memory.

TypeScript Bot (@typescript-bot) perf test this

@typescript-automation

typescript-automation Bot commented Aug 4, 2026

Copy link
Copy Markdown

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

Command Status Results
perf test this ✅ Started 👀 Results

@typescript-automation

Copy link
Copy Markdown

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 119,733 119,733 ~ ~ ~ p=1.000 n=12
Types 99,032 99,032 ~ ~ ~ p=1.000 n=12
Memory Used 151,854k (± 0.44%) 151,257k (± 0.35%) ~ 149,558k 152,418k p=0.198 n=12
Memory Allocs 2,263,136 (± 0.01%) 2,262,965 (± 0.00%) -172 (- 0.01%) 2,262,710 2,263,314 p=0.033 n=12
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Parse Time 0.049s (± 2.62%) 0.051s (± 3.20%) 🔻+0.002s (+ 4.10%) 0.046s 0.056s p=0.030 n=12
Bind Time 0.016s (±10.28%) 0.017s (±14.63%) ~ 0.013s 0.023s p=0.597 n=12
Check Time 0.880s (± 0.59%) 0.881s (± 0.37%) ~ 0.873s 0.890s p=0.619 n=12
Emit Time 0.352s (± 1.17%) 0.347s (± 1.55%) ~ 0.336s 0.363s p=0.182 n=12
Total Time 1.304s (± 0.46%) 1.303s (± 0.67%) ~ 1.284s 1.335s p=0.640 n=12
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=12
Symbols 872,085 (± 0.12%) 872,441 (± 0.11%) ~ 870,385 875,012 p=0.713 n=12
Types 263,961 (± 0.00%) 263,962 (± 0.00%) ~ 263,960 263,964 p=0.072 n=12
Memory Used 806,599k (± 0.06%) 806,677k (± 0.07%) ~ 804,878k 808,291k p=0.514 n=12
Memory Allocs 13,117,402 (± 0.06%) 13,125,384 (± 0.17%) ~ 13,107,593 13,228,441 p=0.671 n=12
Config Time 0.020s (± 0.90%) 0.021s (± 5.71%) ~ 0.020s 0.025s p=0.205 n=12
Parse Time 0.357s (± 1.07%) 0.363s (± 2.61%) ~ 0.340s 0.392s p=0.416 n=12
Bind Time 0.078s (± 9.72%) 0.081s (± 8.99%) ~ 0.073s 0.109s p=0.305 n=12
Check Time 0s 0s ~ ~ ~ p=1.000 n=12
Emit Time 2.030s (± 1.27%) 2.101s (± 2.96%) +0.071s (+ 3.49%) 1.983s 2.347s p=0.017 n=12
Total Time 2.496s (± 1.46%) 2.583s (± 2.96%) +0.087s (+ 3.48%) 2.447s 2.894s p=0.011 n=12
mui-docs - native
Errors 11,277 (± 0.03%) 11,275 (± 0.05%) ~ 11,256 11,282 p=0.746 n=12
Symbols 4,387,605 4,387,802 +197 (+ 0.00%) ~ ~ p=0.000 n=12
Types 1,540,346 1,542,863 +2,517 (+ 0.16%) ~ ~ p=0.000 n=12
Memory Used 4,963,617k (± 0.02%) 4,960,676k (± 0.04%) -2,941k (- 0.06%) 4,955,101k 4,966,060k p=0.014 n=12
Memory Allocs 45,296,076 (± 0.03%) 45,486,394 (± 0.03%) +190,319 (+ 0.42%) 45,443,524 45,526,170 p=0.000 n=12
Config Time 0.019s 0.019s ~ ~ ~ p=1.000 n=12
Parse Time 0.670s (± 2.53%) 0.671s (± 3.78%) ~ 0.562s 0.714s p=0.743 n=12
Bind Time 0.003s (±24.75%) 0.002s (±13.40%) ~ 0.002s 0.003s p=0.491 n=12
Check Time 19.453s (± 0.53%) 19.431s (± 0.50%) ~ 19.253s 19.702s p=0.713 n=12
Emit Time 0.543s (± 3.01%) 0.549s (± 3.23%) ~ 0.519s 0.577s p=0.485 n=12
Total Time 21.565s (± 0.48%) 21.538s (± 0.42%) ~ 21.381s 21.822s p=0.514 n=12
self-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,394,491 1,394,374 -117 (- 0.01%) ~ ~ p=0.000 n=12
Types 442,212 442,315 +103 (+ 0.02%) ~ ~ p=0.000 n=12
Memory Used 1,635,857k (± 0.26%) 1,633,689k (± 0.26%) ~ 1,624,510k 1,647,998k p=0.347 n=12
Memory Allocs 97,083,715 (± 0.04%) 97,056,291 (± 0.03%) ~ 96,946,401 97,106,708 p=0.198 n=12
Config Time 0.005s (±10.14%) 0.005s (±10.49%) ~ 0.004s 0.006s p=0.523 n=12
Parse Time 0.241s (± 2.79%) 0.246s (± 2.57%) ~ 0.224s 0.256s p=0.325 n=12
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Check Time 2.452s (± 0.30%) 2.456s (± 0.46%) ~ 2.436s 2.485s p=0.723 n=12
Emit Time 0.372s (± 2.97%) 0.366s (± 3.96%) ~ 0.335s 0.410s p=0.486 n=12
Total Time 33.271s (± 0.61%) 33.240s (± 0.57%) ~ 32.798s 33.835s p=0.843 n=12
self-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 337,834 337,695 -139 (- 0.04%) ~ ~ p=0.000 n=12
Types 199,561 199,559 -2 (- 0.00%) ~ ~ p=0.000 n=12
Memory Used 318,288k (± 0.03%) 318,327k (± 0.02%) ~ 318,130k 318,604k p=0.989 n=12
Memory Allocs 4,659,157 (± 0.01%) 4,658,322 (± 0.01%) -835 (- 0.02%) 4,656,817 4,659,576 p=0.024 n=12
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=12
Parse Time 0.112s (± 4.27%) 0.112s (± 4.29%) ~ 0.102s 0.128s p=0.744 n=12
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Check Time 1.212s (± 0.79%) 1.207s (± 0.60%) ~ 1.188s 1.229s p=0.417 n=12
Emit Time 0.165s (± 5.77%) 0.160s (± 9.77%) ~ 0.102s 0.191s p=0.788 n=12
Total Time 1.544s (± 0.77%) 1.531s (± 1.30%) ~ 1.453s 1.569s p=0.385 n=12
ts-pre-modules - native
Errors 87 87 ~ ~ ~ p=1.000 n=12
Symbols 302,246 302,244 -2 (- 0.00%) ~ ~ p=0.000 n=12
Types 181,594 181,594 ~ ~ ~ p=1.000 n=12
Memory Used 274,457k (± 0.03%) 274,472k (± 0.02%) ~ 274,317k 274,707k p=0.887 n=12
Memory Allocs 1,661,325 (± 0.01%) 1,661,358 (± 0.01%) ~ 1,661,053 1,661,729 p=0.977 n=12
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Parse Time 0.104s (± 4.66%) 0.099s (± 3.82%) ~ 0.091s 0.111s p=0.085 n=12
Bind Time 0.037s (±12.55%) 0.037s (±14.27%) ~ 0.028s 0.053s p=0.898 n=12
Check Time 0.991s (± 0.67%) 0.993s (± 0.66%) ~ 0.972s 1.005s p=0.640 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 1.146s (± 0.67%) 1.143s (± 0.49%) ~ 1.123s 1.161s p=0.503 n=12
vscode - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 7,673,459 7,666,941 -6,518 (- 0.08%) ~ ~ p=0.000 n=12
Types 2,676,507 2,677,538 +1,031 (+ 0.04%) ~ ~ p=0.000 n=12
Memory Used 5,110,442k (± 0.01%) 5,114,597k (± 0.01%) +4,156k (+ 0.08%) 5,112,959k 5,116,682k p=0.000 n=12
Memory Allocs 38,898,217 (± 0.01%) 38,974,000 (± 0.04%) +75,783 (+ 0.19%) 38,957,128 39,053,984 p=0.000 n=12
Config Time 0.059s (± 0.45%) 0.059s (± 0.55%) ~ 0.058s 0.060s p=0.832 n=12
Parse Time 1.528s (± 1.65%) 1.515s (± 1.93%) ~ 1.430s 1.569s p=0.671 n=12
Bind Time 0.308s (± 0.27%) 0.326s (±11.53%) 🔻+0.018s (+ 5.87%) 0.302s 0.516s p=0.020 n=12
Check Time 9.305s (± 0.44%) 9.326s (± 0.90%) +0.021s (+ 0.23%) 8.919s 9.414s p=0.033 n=12
Emit Time 2.854s (± 4.90%) 2.903s (± 8.01%) ~ 2.771s 4.071s p=0.854 n=12
Total Time 14.069s (± 0.75%) 14.145s (± 1.25%) ~ 14.008s 15.030s p=0.086 n=12
webpack - native
Errors 2 2 ~ ~ ~ p=1.000 n=12
Symbols 211,480 211,480 ~ ~ ~ p=1.000 n=12
Types 340 340 ~ ~ ~ p=1.000 n=12
Memory Used 241,296k (± 0.09%) 241,473k (± 0.12%) ~ 241,023k 242,196k p=0.340 n=12
Memory Allocs 1,000,087 (± 0.22%) 1,001,283 (± 0.38%) ~ 994,747 1,016,199 p=0.660 n=12
Config Time 0.006s 0.006s ~ ~ ~ p=1.000 n=12
Parse Time 0.159s (± 1.94%) 0.159s (± 3.51%) ~ 0.145s 0.167s p=0.618 n=12
Bind Time 0s 0s ~ ~ ~ p=1.000 n=12
Check Time 0s 0s ~ ~ ~ p=1.000 n=12
Emit Time 0.042s (± 8.74%) 0.050s (±17.04%) ~ 0.038s 0.073s p=0.064 n=12
Total Time 0.207s (± 1.48%) 0.215s (± 2.12%) +0.008s (+ 3.78%) 0.205s 0.228s p=0.004 n=12
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,051,574 1,051,028 -546 (- 0.05%) ~ ~ p=0.000 n=12
Types 391,996 392,063 +67 (+ 0.02%) ~ ~ p=0.000 n=12
Memory Used 620,020k (± 0.02%) 619,633k (± 0.02%) -387k (- 0.06%) 619,368k 620,021k p=0.000 n=12
Memory Allocs 4,890,081 (± 0.04%) 4,900,894 (± 0.05%) +10,813 (+ 0.22%) 4,896,252 4,907,906 p=0.000 n=12
Config Time 0.002s 0.002s ~ ~ ~ p=1.000 n=12
Parse Time 0.113s (± 3.61%) 0.115s (± 2.05%) ~ 0.108s 0.121s p=0.222 n=12
Bind Time 0.038s (±18.09%) 0.035s (±19.76%) ~ 0.026s 0.059s p=0.445 n=12
Check Time 1.050s (± 0.85%) 1.058s (± 0.86%) ~ 1.037s 1.083s p=0.173 n=12
Emit Time 0.001s 0.001s (±19.81%) ~ 0.000s 0.001s p=1.000 n=12
Total Time 1.210s (± 1.04%) 1.217s (± 0.87%) ~ 1.184s 1.239s p=0.285 n=12
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 12
Baseline baseline 12

lsp

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsLSP - native
Req 1 - updateOpen 13ms (± 2.32%) 14ms (±11.64%) ~ 13ms 22ms p=1.000 n=12
Req 2 - geterr 648ms (± 1.19%) 643ms (± 1.58%) ~ 617ms 672ms p=0.504 n=12
Req 3 - references 50ms (± 7.21%) 53ms (± 9.41%) ~ 47ms 68ms p=0.281 n=12
Req 4 - navto 24ms (±17.37%) 21ms (±17.23%) ~ 18ms 34ms p=0.315 n=12
Req 5 - completionInfo count 1,363 1,363 ~ ~ ~ p=1.000 n=12
Req 5 - completionInfo 29ms (±13.48%) 30ms (± 9.15%) ~ 23ms 36ms p=0.876 n=12
CompilerLSP - native
Req 1 - updateOpen 14ms (± 6.99%) 14ms (± 4.69%) ~ 13ms 16ms p=0.927 n=12
Req 2 - geterr 359ms (± 1.69%) 358ms (± 1.72%) ~ 341ms 374ms p=0.854 n=12
Req 3 - references 62ms (± 9.34%) 65ms (± 8.20%) ~ 54ms 83ms p=0.468 n=12
Req 4 - navto 24ms (±16.55%) 19ms (± 5.89%) ~ 17ms 23ms p=0.131 n=12
Req 5 - completionInfo count 1,525 1,525 ~ ~ ~ p=1.000 n=12
Req 5 - completionInfo 26ms (±10.86%) 27ms (± 8.76%) ~ 21ms 33ms p=0.832 n=12
System info unknown
Hosts
  • native
Scenarios
  • CompilerLSP - native
  • Compiler-UnionsLSP - native
  • xstate-main-1-LSP - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

startup

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
lsp-startup - native
Execution time 4.73ms (±365.09%) 4.72ms (±365.10%) -0.01ms (- 0.13%) 0.00ms 473.21ms p=0.000 n=1200
tsgo-startup - native
Execution time 5.95ms (±365.11%) 5.99ms (±365.11%) +0.03ms (+ 0.55%) 0.00ms 606.48ms p=0.000 n=1200
System info unknown
Hosts
  • native
Scenarios
  • lsp-startup - native
  • tsgo-startup - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

Developer Information:

Download Benchmarks

@weswigham Wesley Wigham (weswigham) 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.

Hm, so we're spending more memory just to track dupe suggestions upfront, only to dedupe them later (why is why the issue was partially us keeping a lot of copies around but only during the build); any reason we're not deduping all diagnostic collections on .Add? We always do a SortAndDeduplicate in collectCheckerDiagnostics as-is when we could just be sorting/deduping upfront, no? The lazy sort-on-demand in the diagnostic collection and then sort-again-and-also-dedupe-in-program we're doing right now is sorta a weird division of labor, right? Surely maintaining a sorted/deduped list upfront is better at this point?

@jakebailey

Copy link
Copy Markdown
Member Author

Part of the problem with the checker diags is that we add them and then modify them, which makes deduping sort of annoying. We could fix that, though.

@jakebailey

Copy link
Copy Markdown
Member Author

I took a stab at it. PTAL

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

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

internal/checker/checker.go:2536

  • The new deferred kinds permanently grow each source file's deferredNodes backing storage. checkDeferredNodes drains the set with Clear, but collections.OrderedSet.Clear explicitly retains both the key slice and map allocation (internal/collections/ordered_set.go:38-41, ordered_map.go:181-187). Because SourceFileLinks lives for the checker lifetime, registering every object literal and JSX attribute leaves capacity proportional to all such nodes resident after checking, undermining this PR's memory-regression fix. Release/reinitialize the set after the one-shot deferred pass rather than retaining its storage.

Comment on lines +178 to +180
key := getDiagnosticLocationKey(diagnostic)
if existing := c.diagnosticIndex[key]; existing != nil {
if EqualDiagnostics(existing, diagnostic) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ram use regression from new @deprecated diagnostics

4 participants