Skip to content

fix: Corsa differences in export= module augmentation#4446

Open
pratheeknathani wants to merge 2 commits into
microsoft:mainfrom
pratheeknathani:fix-3481
Open

fix: Corsa differences in export= module augmentation#4446
pratheeknathani wants to merge 2 commits into
microsoft:mainfrom
pratheeknathani:fix-3481

Conversation

@pratheeknathani

Copy link
Copy Markdown

Summary

Test setup: // /node_modules/foo/index.d.ts export = foo; declare namespace foo { export type T = number; } // /a.ts import * as foo from "foo"; declare module "foo" { export function f(): T; // OK in TS } Corsa wrongly reported TS4060: Return type of exported function has or is using private name 'T' when emitting...

What changed

Test setup:

// /node_modules/foo/index.d.ts
export = foo;
declare namespace foo {
 export type T = number;
}

// /a.ts
import * as foo from "foo";
declare module "foo" {
 export function f(): T; // OK in TS
}

Corsa wrongly reported TS4060: Return type of exported function has or is using private name 'T' when emitting a.d.ts. As a result a.d.ts was never emitted.

During declaration emit, T is resolved correctly, but its visibility is checked through its container, the namespace foo. foo is not marked export; it is exported only through export = foo in index.d.ts. TypeScript makes such an export = target visible by calling collectLinkedAliases(id, /*setVisibility*/ true) inside checkExportAssignment, which runs while checking every file, including non-emitted ones like index.d.ts.

Corsa moved that alias-visibility marking into the emit resolver (PrecalculateDeclarationEmitVisibility), which only walks the file currently being emitted (a.ts/b.ts). The export = foo lives in index.d.ts, which is never emitted, so foo (and therefore T) was never marked visible. determineIfDeclarationIsVisible then fell through to isGlobalSourceFile(parent) and returned false, producing the spurious TS4060.

Issue

Fixes #3481

Issue: #3481

Diffstat

internal/checker/emitresolver.go | 26 +++++++++++++++++++++
 ...signmentMembersVisibleInAugmentation.errors.txt | 23 ------------------
 ...exportAssignmentMembersVisibleInAugmentation.js | 5 ++++
 ...tAssignmentMembersVisibleInAugmentation.js.diff | 14 -----------
 ...entMembersVisibleInAugmentation.errors.txt.diff | 27 ----------------------
 5 files changed, 31 insertions(+), 64 deletions(-)

Testing

  • Ran the relevant tests and linter for the changed files while developing.

  • Kept the change minimal and focused on this one issue.

AI assistance

I used GitHub Copilot to help write parts of this change. I've reviewed and tested it myself, I understand what it does, and I'll follow up on any review feedback.

Copilot AI review requested due to automatic review settings June 25, 2026 20:15

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

Fixes a declaration-emit visibility edge case where an export = target (and its nested exported members) wasn’t treated as externally visible during .d.ts emit, causing a spurious TS4060 and preventing declaration output for a module augmentation scenario.

Changes:

  • Treat declarations that are the target of an export = in their containing external module as visible during declaration emit visibility checks.
  • Update submodule baselines to remove the erroneous TS4060 diagnostic and restore a.d.ts emission for the affected test.
  • Remove now-unneeded triaged diff baselines for this case.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
internal/checker/emitresolver.go Adds an export =-target visibility fast-path in determineIfDeclarationIsVisible.
testdata/baselines/reference/submoduleTriaged/compiler/exportAssignmentMembersVisibleInAugmentation.errors.txt.diff Removes the triaged diff that captured the now-fixed TS4060 discrepancy.
testdata/baselines/reference/submodule/compiler/exportAssignmentMembersVisibleInAugmentation.errors.txt Removes the error baseline now that TS4060 no longer occurs.
testdata/baselines/reference/submodule/compiler/exportAssignmentMembersVisibleInAugmentation.js Updates baseline to include the restored a.d.ts output.
testdata/baselines/reference/submodule/compiler/exportAssignmentMembersVisibleInAugmentation.js.diff Removes the diff baseline since the output now matches the reference expectation.

Comment on lines -13 to -15
export function f(): T; // OK
~
!!! error TS4060: Return type of exported function has or is using private name 'T'.

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.

Odd that this begins working

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, this lines up with what upstream TypeScript already does here (which is why there was a submoduleTriaged diff recording Corsa diverging from it).

TS marks foo/T visible via collectLinkedAliases(setVisibility=true) on the export = foo in index.d.ts, but Corsa moved that into PrecalculateDeclarationEmitVisibility, which only walks the file being emitted (a.ts), so the export = in the never-emitted index.d.ts was missed and the target fell through to isGlobalSourceFile and returned false. The fix just treats a declaration that's the export = target of its own module as visible, so it matches TS again.

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.

This sort of cross-file analysis is very spooky... It means emit can differ based on whether or not we use the checker for emit or not. Probably that is inevitable for this particular location, however

@jakebailey

Copy link
Copy Markdown
Member

@typescript-bot perf test this faster

@typescript-automation

typescript-automation Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

Command Status Results
perf test this faster ✅ Started 👀 Results

@typescript-automation

Copy link
Copy Markdown

@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 4 4 ~ ~ ~ p=1.000 n=6
Symbols 81,773 (± 0.05%) 81,811 (± 0.04%) ~ 81,770 81,853 p=0.128 n=6
Types 98,821 98,821 ~ ~ ~ p=1.000 n=6
Memory Used 180,225k (± 0.33%) 179,941k (± 0.28%) ~ 179,281k 180,780k p=0.230 n=6
Memory Allocs 2,547,020 (± 0.01%) 2,547,001 (± 0.01%) ~ 2,546,688 2,547,441 p=0.936 n=6
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Parse Time 0.066s (± 8.59%) 0.063s (± 5.69%) ~ 0.059s 0.067s p=0.466 n=6
Bind Time 0.018s (±30.58%) 0.016s (±24.36%) ~ 0.011s 0.023s p=1.000 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 0.872s (± 1.13%) 0.869s (± 0.28%) ~ 0.864s 0.871s p=0.686 n=6
Total Time 0.957s (± 1.40%) 0.949s (± 0.96%) ~ 0.935s 0.963s p=0.336 n=6
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=6
Symbols 876,226 (± 0.10%) 877,045 (± 0.17%) ~ 875,879 879,930 p=0.298 n=6
Types 263,750 (± 0.00%) 263,750 (± 0.00%) ~ 263,748 263,751 p=1.000 n=6
Memory Used 830,189k (± 0.05%) 830,701k (± 0.07%) ~ 830,267k 831,792k p=0.128 n=6
Memory Allocs 12,654,301 (± 0.12%) 12,650,638 (± 0.09%) ~ 12,639,416 12,664,479 p=0.575 n=6
Config Time 0.017s 0.017s (± 4.71%) ~ 0.017s 0.019s p=0.405 n=6
Parse Time 0.234s (± 4.58%) 0.237s (± 4.30%) ~ 0.228s 0.255s p=0.419 n=6
Bind Time 0.054s (±19.40%) 0.057s (±35.88%) ~ 0.036s 0.087s p=0.688 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 1.881s (± 0.77%) 1.908s (± 1.93%) ~ 1.868s 1.958s p=0.471 n=6
Total Time 2.202s (± 0.64%) 2.232s (± 1.04%) +0.030s (+ 1.36%) 2.207s 2.260s p=0.016 n=6
mui-docs - native
Errors 11,282 11,280 (± 0.04%) ~ 11,271 11,282 p=0.074 n=6
Symbols 4,747,930 4,747,930 ~ ~ ~ p=1.000 n=6
Types 1,585,409 1,585,409 ~ ~ ~ p=1.000 n=6
Memory Used 5,883,975k (± 0.03%) 5,882,408k (± 0.03%) ~ 5,879,606k 5,885,692k p=0.298 n=6
Memory Allocs 50,872,251 (± 0.14%) 50,813,209 (± 0.06%) ~ 50,773,375 50,858,662 p=0.093 n=6
Config Time 0.017s (± 9.79%) 0.017s (± 6.94%) ~ 0.016s 0.019s p=0.445 n=6
Parse Time 0.529s (± 5.37%) 0.545s (± 2.62%) ~ 0.525s 0.561s p=0.378 n=6
Bind Time 0.002s 0.002s ~ ~ ~ p=1.000 n=6
Check Time 17.399s (± 0.38%) 17.438s (± 0.67%) ~ 17.356s 17.651s p=0.470 n=6
Emit Time 0.524s (±30.36%) 0.520s (±31.02%) ~ 0.430s 0.847s p=0.871 n=6
Total Time 19.278s (± 0.89%) 19.287s (± 1.42%) ~ 19.091s 19.824s p=0.936 n=6
self-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,394,269 1,394,269 ~ ~ ~ p=1.000 n=6
Types 442,235 442,235 ~ ~ ~ p=1.000 n=6
Memory Used 1,650,893k (± 0.33%) 1,649,859k (± 0.29%) ~ 1,643,208k 1,655,768k p=0.810 n=6
Memory Allocs 98,387,513 (± 0.04%) 98,396,273 (± 0.05%) ~ 98,336,835 98,481,642 p=0.936 n=6
Config Time 0.026s (±15.49%) 0.017s (±47.62%) 🟩-0.009s (-34.81%) 0.007s 0.027s p=0.037 n=6
Parse Time 0.272s (± 4.54%) 0.266s (± 4.89%) ~ 0.246s 0.283s p=0.470 n=6
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Check Time 2.336s (± 0.61%) 2.326s (± 0.64%) ~ 2.310s 2.354s p=0.297 n=6
Emit Time 0.288s (± 2.23%) 0.283s (± 3.40%) ~ 0.270s 0.299s p=0.297 n=6
Total Time 30.568s (± 0.64%) 30.244s (± 1.16%) ~ 29.731s 30.731s p=0.093 n=6
self-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 337,637 337,637 ~ ~ ~ p=1.000 n=6
Types 199,520 199,520 ~ ~ ~ p=1.000 n=6
Memory Used 332,423k (± 0.05%) 332,469k (± 0.03%) ~ 332,328k 332,628k p=0.689 n=6
Memory Allocs 4,760,753 (± 0.02%) 4,760,374 (± 0.01%) ~ 4,759,773 4,760,776 p=0.471 n=6
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=6
Parse Time 0.131s (± 3.29%) 0.125s (± 3.90%) ~ 0.120s 0.133s p=0.064 n=6
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=6
Check Time 1.393s (± 0.95%) 1.385s (± 0.58%) ~ 1.376s 1.397s p=0.297 n=6
Emit Time 0.125s (±11.12%) 0.124s (± 3.79%) ~ 0.118s 0.131s p=1.000 n=6
Total Time 1.709s (± 1.23%) 1.686s (± 0.47%) -0.022s (- 1.30%) 1.676s 1.695s p=0.037 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,703k (± 0.01%) 133,731k (± 0.02%) ~ 133,698k 133,764k p=0.128 n=6
Memory Allocs 182,584 (± 0.20%) 182,683 (± 0.14%) ~ 182,228 182,911 p=0.378 n=6
Config Time 0.001s (±48.94%) 0.001s ~ ~ ~ p=0.405 n=6
Parse Time 0.110s (± 3.54%) 0.109s (± 4.86%) ~ 0.106s 0.120s p=0.807 n=6
Bind Time 0.038s (± 5.12%) 0.035s (±15.33%) ~ 0.029s 0.044s p=0.142 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.152s (± 3.65%) 0.148s (± 4.42%) ~ 0.142s 0.156s p=0.260 n=6
vscode - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 6,793,987 6,793,987 ~ ~ ~ p=1.000 n=6
Types 2,402,155 2,402,155 ~ ~ ~ p=1.000 n=6
Memory Used 4,619,034k (± 0.01%) 4,619,215k (± 0.02%) ~ 4,617,943k 4,620,572k p=0.810 n=6
Memory Allocs 32,790,166 (± 0.04%) 32,788,462 (± 0.03%) ~ 32,778,046 32,802,967 p=0.936 n=6
Config Time 0.074s (±12.20%) 0.074s (± 9.55%) ~ 0.068s 0.084s p=1.000 n=6
Parse Time 0.891s (± 3.76%) 0.886s (± 2.80%) ~ 0.852s 0.910s p=0.873 n=6
Bind Time 0.145s (±14.31%) 0.138s (± 2.53%) ~ 0.133s 0.144s p=1.000 n=6
Check Time 8.948s (± 0.65%) 8.903s (± 0.29%) ~ 8.855s 8.927s p=0.054 n=6
Emit Time 2.471s (± 9.01%) 2.483s (± 3.54%) ~ 2.322s 2.575s p=0.230 n=6
Total Time 12.548s (± 1.13%) 12.501s (± 0.97%) ~ 12.293s 12.639s p=0.471 n=6
webpack - native
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 183,526 183,526 ~ ~ ~ p=1.000 n=6
Types 340 340 ~ ~ ~ p=1.000 n=6
Memory Used 223,356k (± 0.10%) 223,412k (± 0.09%) ~ 223,162k 223,580k p=0.575 n=6
Memory Allocs 1,080,282 (± 0.35%) 1,080,195 (± 0.47%) ~ 1,073,344 1,087,827 p=0.936 n=6
Config Time 0.010s (±10.67%) 0.012s (±14.99%) ~ 0.009s 0.014s p=0.051 n=6
Parse Time 0.155s (± 4.24%) 0.155s (± 4.16%) ~ 0.146s 0.163s p=1.000 n=6
Bind Time 0s 0s ~ ~ ~ p=1.000 n=6
Check Time 0s 0s ~ ~ ~ p=1.000 n=6
Emit Time 0.042s (±16.10%) 0.036s (±20.54%) ~ 0.030s 0.050s p=0.108 n=6
Total Time 0.207s (± 3.56%) 0.203s (± 5.72%) ~ 0.193s 0.224s p=0.261 n=6
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,065,147 1,065,147 ~ ~ ~ p=1.000 n=6
Types 389,312 389,312 ~ ~ ~ p=1.000 n=6
Memory Used 643,885k (± 0.02%) 643,875k (± 0.01%) ~ 643,784k 643,930k p=0.689 n=6
Memory Allocs 5,103,085 (± 0.13%) 5,098,278 (± 0.04%) ~ 5,095,997 5,102,191 p=0.093 n=6
Config Time 0.005s (±11.05%) 0.005s (± 8.44%) ~ 0.004s 0.005s p=0.595 n=6
Parse Time 0.131s (± 4.93%) 0.139s (± 4.07%) ~ 0.132s 0.148s p=0.072 n=6
Bind Time 0.035s (±27.16%) 0.035s (±25.34%) ~ 0.026s 0.047s p=0.688 n=6
Check Time 1.306s (± 1.59%) 1.306s (± 1.03%) ~ 1.292s 1.330s p=0.810 n=6
Emit Time 0.001s 0.001s ~ ~ ~ p=1.000 n=6
Total Time 1.482s (± 1.09%) 1.490s (± 1.14%) ~ 1.475s 1.521s p=0.336 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

The PR deleted submoduleTriaged/compiler/exportAssignmentMembersVisibleInAugmentation.errors.txt.diff (the diff is now resolved) but left its entry in testdata/submoduleTriaged.txt. TestSubmoduleTriagedFilesExist in internal/testutil/baseline asserts every listed file exists, so it failed across every go test ./... job (no-submodules, noembed, race, ubuntu, windows, concurrent, generate). Remove the stale line; the issue-3481 group keeps augmentExportEquals2.errors.txt.diff, which is still a tracked diff.
@pratheeknathani

Copy link
Copy Markdown
Author

Pushed ad92cc3 to fix CI on this PR.

The earlier commit correctly deleted the now-resolved triaged baseline submoduleTriaged/compiler/exportAssignmentMembersVisibleInAugmentation.errors.txt.diff, but left its entry in testdata/submoduleTriaged.txt. TestSubmoduleTriagedFilesExist (in internal/testutil/baseline) asserts every listed file exists, so it failed across all go test ./... jobs (no-submodules, noembed, race, ubuntu, windows, concurrent, generate).

The follow-up removes that single stale line. The issue-3481 group still keeps augmentExportEquals2.errors.txt.diff, which remains a tracked diff. Verified locally with go test ./internal/testutil/baseline/ and the full testrunner suite (TestLocal + TestSubmodule).

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.

Corsa differences in export= module augmentation

3 participants