Skip to content

Mark class property initializers as outside of CFA containers - #63310

Merged
Ryan Cavanaugh (RyanCavanaugh) merged 3 commits into
mainfrom
copilot/fix-narrow-inference-regression
Mar 31, 2026
Merged

Mark class property initializers as outside of CFA containers#63310
Ryan Cavanaugh (RyanCavanaugh) merged 3 commits into
mainfrom
copilot/fix-narrow-inference-regression

Conversation

CopilotAI commented Mar 27, 2026

Copy link
Copy Markdown
Contributor
  • Investigate root cause: PR Improve inference by not considering thisless functions to be context-sensitive #62243 removed PropertyDeclaration from ContainerFlags.IsControlFlowContainer in binder.ts
  • Root cause confirmed: property initializers no longer have isolated flow scopes, causing module-level narrowing (const DEFAULT: AB = 'A'"A") to leak into class property type inference
  • Remove debug code from checker.ts
  • Fix: restore PropertyDeclaration as IsControlFlowContainer in binder.ts
  • Add regression test classPropertyInferenceFromBroaderTypeConst.ts
  • Verify test passes with correct types (D: AB, this.D: AB)
  • Run full test suite

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

CopilotAIand others added 2 commits March 28, 2026 00:13
Agent-Logs-Url: https://github.com/microsoft/TypeScript/sessions/c865d3f5-aaf0-4dfc-8051-47e4fe1b3e86
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
return ContainerFlags.IsControlFlowContainer;

case SyntaxKind.PropertyDeclaration:
return (node as PropertyDeclaration).initializer ? ContainerFlags.IsControlFlowContainer : ContainerFlags.None;

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.

It would be worth rechecking if this now shouldn't include PropagatesThisKeyword too

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.

Mateusz Burzyński (@Andarist) how does this manifest? I tried to cook up a repro but failed

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.

At the time of writing the comment, I didn't think of any specific case. I just knew this change might change the presence of this flag on some property declarations so it would be worth double-checking if that can lead to some adverse effects.

But like you and your agents, my agents and I can't find any either. 🤪

So my vote goes for "internal change without public-facing downsides"

@RyanCavanaugh

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) test it

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

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

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

@typescript-bot

Copy link
Copy Markdown
Contributor

Hey Ryan Cavanaugh (@RyanCavanaugh), the results of running the DT tests are ready.

Everything looks the same!

You can check the log here.

@typescript-bot

Copy link
Copy Markdown
Contributor

Ryan Cavanaugh (@RyanCavanaugh) Here are the results of running the user tests with tsc comparing main and refs/pull/63310/merge:

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Git clone failed"

Otherwise...

Everything looks good!

@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) marked this pull request as ready for review March 28, 2026 16:50
CopilotAI review requested due to automatic review settings March 28, 2026 16:50

CopilotAI 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

Fixes a TypeScript 6.0 regression where module-level narrowing from a broader-typed const could leak into class property initializer inference, by restoring an isolated control-flow scope for property initializers in the binder.

Changes:

  • Restore SyntaxKind.PropertyDeclaration as a control-flow container (when it has an initializer) in getContainerFlags.
  • Add a compiler regression test ensuring class/static properties infer the declared wider type (AB) rather than a narrowed literal.
  • Add new baselines (.types, .symbols, .js) for the regression test.

Reviewed changes

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

Show a summary per file
FileDescription
src/compiler/binder.tsRestores property declarations with initializers as isolated control-flow containers to prevent narrowing leakage into inference.
tests/cases/compiler/classPropertyInferenceFromBroaderTypeConst.tsNew regression test covering instance and static class property inference from a broader-typed const.
tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.typesBaseline verifying inferred types (e.g., D: AB, SD: AB) and switch narrowing behavior.
tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.symbolsBaseline verifying symbol binding for the new test.
tests/baselines/reference/classPropertyInferenceFromBroaderTypeConst.jsBaseline verifying emit output for the new test.

Comment threadsrc/compiler/binder.ts
@typescript-bot

Copy link
Copy Markdown
Contributor

Ryan Cavanaugh (@RyanCavanaugh) Here are the results of running the top 400 repos with tsc comparing main and refs/pull/63310/merge:

Everything looks good!

@typescript-bot

Copy link
Copy Markdown
Contributor

Ryan Cavanaugh (@RyanCavanaugh)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-Unions - node (v18.15.0, x64)
Errors33~~~p=1.000 n=6
Symbols82,52182,521~~~p=1.000 n=6
Types125,280125,280~~~p=1.000 n=6
Memory used275,005k (± 0.50%)276,127k (± 0.68%)~274,392k277,890kp=0.936 n=6
Parse Time1.31s (± 0.79%)1.31s (± 0.80%)~1.29s1.32sp=0.801 n=6
Bind Time0.76s0.76s (± 0.54%)~0.75s0.76sp=0.405 n=6
Check Time14.28s (± 1.15%)14.19s (± 0.49%)~14.10s14.26sp=0.336 n=6
Emit Time2.69s (± 0.61%)2.69s (± 0.61%)~2.67s2.72sp=0.370 n=6
Total Time19.04s (± 0.91%)18.94s (± 0.43%)~18.83s19.02sp=0.296 n=6
angular-1 - node (v18.15.0, x64)
Errors33~~~p=1.000 n=6
Symbols959,140959,140~~~p=1.000 n=6
Types416,033416,033~~~p=1.000 n=6
Memory used1,261,053k (± 0.01%)1,261,321k (± 0.00%)+268k (+ 0.02%)1,261,239k1,261,396kp=0.005 n=6
Parse Time8.01s (± 1.05%)8.05s (± 0.85%)~7.98s8.16sp=0.520 n=6
Bind Time2.40s (± 0.82%)2.39s (± 1.10%)~2.35s2.42sp=0.359 n=6
Check Time38.81s (± 0.42%)38.72s (± 0.53%)~38.49s38.96sp=0.470 n=6
Emit Time18.11s (± 0.48%)18.08s (± 0.65%)~17.85s18.18sp=0.689 n=6
Total Time67.33s (± 0.29%)67.23s (± 0.40%)~67.02s67.63sp=0.689 n=6
mui-docs - node (v18.15.0, x64)
Errors11,13611,136~~~p=1.000 n=6
Symbols2,202,1482,202,148~~~p=1.000 n=6
Types764,674764,674~~~p=1.000 n=6
Memory used2,642,677k (± 0.00%)2,642,601k (± 0.00%)~2,642,416k2,642,791kp=0.298 n=6
Parse Time9.52s (± 0.25%)9.52s (± 0.18%)~9.49s9.54sp=1.000 n=6
Bind Time2.50s (± 1.40%)2.53s (± 0.63%)~2.51s2.55sp=0.256 n=6
Check Time86.29s (± 1.63%)87.59s (± 2.03%)~85.49s90.33sp=0.298 n=6
Emit Time0.36s (± 2.48%)0.37s (± 3.17%)~0.35s0.38sp=0.214 n=6
Total Time98.68s (± 1.41%)100.01s (± 1.78%)~97.92s102.78sp=0.173 n=6
self-build-src - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,227,3631,227,363~~~p=1.000 n=6
Types267,197267,198+1 (+ 0.00%)~~p=0.001 n=6
Memory used2,779,598k (± 9.86%)2,779,994k (± 5.35%)~2,718,790k3,083,850kp=0.378 n=6
Parse Time6.58s (± 1.21%)6.55s (± 0.81%)~6.51s6.65sp=0.689 n=6
Bind Time2.24s (± 1.18%)2.24s (± 0.68%)~2.21s2.25sp=0.872 n=6
Check Time43.09s (± 0.51%)42.85s (± 0.83%)~42.41s43.40sp=0.173 n=6
Emit Time3.56s (± 2.90%)3.59s (± 3.14%)~3.48s3.76sp=0.873 n=6
Total Time55.48s (± 0.55%)55.22s (± 0.75%)~54.69s55.73sp=0.575 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,227,3631,227,363~~~p=1.000 n=6
Types267,197267,198+1 (+ 0.00%)~~p=0.001 n=6
Memory used2,785,493k (± 8.21%)2,785,042k (± 0.02%)~2,784,403k2,785,587kp=1.000 n=6
Parse Time6.73s (± 1.23%)6.69s (± 0.73%)~6.63s6.75sp=0.689 n=6
Bind Time2.23s (± 0.52%)2.26s (± 1.74%)~2.22s2.32sp=0.127 n=6
Check Time43.00s (± 0.85%)42.82s (± 0.55%)~42.52s43.22sp=0.298 n=6
Emit Time3.52s (± 4.16%)3.58s (± 5.07%)~3.41s3.88sp=0.521 n=6
Total Time55.52s (± 0.69%)55.35s (± 0.75%)~54.85s55.91sp=0.575 n=6
self-compiler - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols261,660261,660~~~p=1.000 n=6
Types104,322104,323+1 (+ 0.00%)~~p=0.001 n=6
Memory used439,336k (± 0.01%)439,347k (± 0.01%)~439,248k439,402kp=0.630 n=6
Parse Time3.52s (± 0.72%)3.52s (± 0.54%)~3.49s3.54sp=0.933 n=6
Bind Time1.34s (± 1.05%)1.38s (± 1.33%)+0.04s (+ 2.86%)1.36s1.40sp=0.008 n=6
Check Time19.32s (± 0.48%)19.30s (± 0.39%)~19.21s19.39sp=0.689 n=6
Emit Time1.55s (± 1.49%)1.56s (± 0.94%)~1.54s1.58sp=0.869 n=6
Total Time25.74s (± 0.28%)25.76s (± 0.35%)~25.63s25.88sp=0.688 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors271271~~~p=1.000 n=6
Symbols225,897225,897~~~p=1.000 n=6
Types93,56493,564~~~p=1.000 n=6
Memory used371,594k (± 0.01%)371,632k (± 0.02%)~371,573k371,807kp=0.471 n=6
Parse Time2.85s (± 0.79%)2.85s (± 0.60%)~2.83s2.87sp=0.807 n=6
Bind Time1.64s (± 0.99%)1.64s (± 0.71%)~1.62s1.65sp=0.568 n=6
Check Time17.46s (± 0.22%)17.44s (± 0.50%)~17.29s17.53sp=0.685 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time21.95s (± 0.26%)21.94s (± 0.43%)~21.77s22.01sp=0.686 n=6
vscode - node (v18.15.0, x64)
Errors00~~~p=NaN n=0
Symbols00~~~p=NaN n=0
Types00~~~p=NaN n=0
Memory used0k0k~~~p=NaN n=0
Parse Time0s0s~~~p=NaN n=0
Bind Time0s0s~~~p=NaN n=0
Check Time0s0s~~~p=NaN n=0
Emit Time0s0s~~~p=NaN n=0
Total Time0s0s~~~p=NaN n=0
webpack - node (v18.15.0, x64)
Errors88~~~p=1.000 n=6
Symbols408,835408,835~~~p=1.000 n=6
Types186,908186,908~~~p=1.000 n=6
Memory used570,889k (± 0.02%)570,961k (± 0.02%)~570,797k571,065kp=0.298 n=6
Parse Time4.75s (± 0.64%)4.73s (± 0.84%)~4.66s4.78sp=0.517 n=6
Bind Time2.02s (± 0.88%)2.05s (± 1.62%)~2.00s2.09sp=0.063 n=6
Check Time24.48s (± 0.42%)24.47s (± 0.54%)~24.29s24.62sp=0.873 n=6
Emit Time0.00s (±154.76%)0.01s (±77.38%)~0.00s0.01sp=0.311 n=6
Total Time31.25s (± 0.41%)31.25s (± 0.58%)~30.99s31.49sp=1.000 n=6
xstate-main - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols781,066781,066~~~p=1.000 n=6
Types227,795227,795~~~p=1.000 n=6
Memory used697,180k (± 0.01%)697,166k (± 0.01%)~697,097k697,250kp=0.575 n=6
Parse Time3.98s (± 0.44%)3.98s (± 0.63%)~3.95s4.01sp=1.000 n=6
Bind Time1.34s (± 0.47%)1.35s (± 0.56%)~1.34s1.36sp=0.081 n=6
Check Time19.37s (± 0.45%)19.43s (± 0.46%)~19.33s19.53sp=0.261 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time24.68s (± 0.41%)24.75s (± 0.34%)~24.64s24.85sp=0.228 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

@RyanCavanaughRyan Cavanaugh (RyanCavanaugh) changed the title [WIP] Fix regression in 6.0: Broader type inference issueMark class property initializers as outside of CFA containersMar 30, 2026
Merged via the queue into main with commit 0844c43Mar 31, 2026
27 checks passed
@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) deleted the copilot/fix-narrow-inference-regression branch March 31, 2026 15:54
@jakebailey

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) cherry-pick this to release-6.0

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

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

CommandStatusResults
cherry-pick this to release-6.0✅ Started✅ Results

TypeScript Bot (typescript-bot) pushed a commit that referenced this pull request Mar 31, 2026
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
@typescript-bot

Copy link
Copy Markdown
Contributor

Hey, Jake Bailey (@jakebailey)! I've created #63327 for you.

Ryan Cavanaugh (RyanCavanaugh) added a commit that referenced this pull request Apr 6, 2026
…e-6.0 (#63327)
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Sign up for freeto 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.

Regression in 6.0: type inferred from const with broader type is too narrow

7 participants

@RyanCavanaugh@typescript-bot@jakebailey@Andarist@DanielRosenwasser