Skip to content

Fix declaration emit renaming value references to shadowed type parameters - #64951

Open
Mariana Castro (maricastroc) wants to merge 4 commits into
microsoft:mainfrom
maricastroc:fix/declaration-emit-type-parameter-value-references
Open

Mariana Castro (maricastroc) wants to merge 4 commits into
microsoft:mainfrom
maricastroc:fix/declaration-emit-type-parameter-value-references

Conversation

@maricastroc

Copy link
Copy Markdown
Contributor

Fixes #64706

Problem

A type parameter and a parameter with the same name (<value>(value: value)) share one symbol. When declaration emit reuses existing type nodes and renames a shadowed inner type parameter (for example to value_1), the identifier rewriter in nodecopy.go only checked whether the symbol had TypeParameter flags. So references that need the value meaning were renamed too:

  • type predicate and assertion targets (value is ..., asserts value, asserts value is ...)
  • typeof value and typeof value.member
  • computed property names ({ [value]: number })

This produced declarations that don't compile (TS1225, TS2693), or, when another parameter was already named value_1, declarations that compile but refer to the wrong parameter.

Fix

attachSymbolToLeftmostIdentifier now receives the meaning of the reference and only uses typeParameterToName when the symbol is a type parameter in that meaning. The type parameter accessibility shortcut in trackExistingEntityName uses the same check, so value references to the shared symbol go through the normal accessibility check.

Before:

export declare function predicate<value>(value: value): <value_1>(value: value_1) => value_1 is value_1 & string;
export declare function capturedQuery<value>(value: value): <value_1>(value: value_1, value_1: number) => typeof value_1;

After:

export declare function predicate<value>(value: value): <value_1>(value: value_1) => value is value_1 & string;
export declare function capturedQuery<value>(value: value): <value_1>(value: value_1, value_1: number) => typeof value;

Tests

declarationEmitShadowedTypeParameterSharesParameterName.ts covers type predicates, both assertion forms, typeof in return and parameter types, qualified typeof, computed property names, the cases where another parameter is already named value_1, nested functions, arrow functions, object methods, and a local typeof that refers to a different symbol. Thanks Jason Kuhrt (@jasonkuhrt) for the extra cases in the issue.

I also checked the emitted declarations with a consumer (skipLibCheck: false): it type-checks, and the predicates, assertions and typeof return types act on the first parameter, as in the source.

npx hereby validate passes.

This PR was prepared with AI assistance (Claude Code).

🤖 Generated with Claude Code

…eters

A type parameter and a parameter with the same name share one symbol.
When reusing nodes, only treat that symbol as a type parameter if the
reference is in a type parameter meaning, so predicate targets and
`typeof` operands keep the parameter's name and value references go
through the regular accessibility check.
…n emit tests

Add plain and captured assertion predicates and a computed property name
whose expression refers to a parameter sharing its name with a shadowed
type parameter.

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.

🟢 Approval recommended

The narrowly scoped checks preserve value references while retaining type-parameter renaming, and the regression baselines cover the reported failure modes.

No open issues 🎉

What changed in this PR

Fixes #64706 in the native TypeScript compiler by preserving value-reference names when declaration emit renames shadowed type parameters.

Changes:

  • Makes identifier rewriting and accessibility checks respect whether a reference uses the type or value meaning.
  • Adds regression coverage for predicates, assertions, type queries, computed properties, and parameter-name collisions.
  • Records expected declaration output, types, and symbol bindings.
File Description
tsc/​internal/​checker/​nodecopy.go Restricts type-parameter renaming to references with the appropriate meaning.
tsc/​testdata/​tests/​cases/​compiler/​declarationEmitShadowedTypeParameterSharesParameterName.ts Adds regression cases for shared type/value names.
tsc/​testdata/​baselines/​reference/​compiler/​declarationEmitShadowedTypeParameterSharesParameterName.types Records expected types with preserved value references.
tsc/​testdata/​baselines/​reference/​compiler/​declarationEmitShadowedTypeParameterSharesParameterName.symbols Records symbol bindings for the regression cases.
tsc/​testdata/​baselines/​reference/​compiler/​declarationEmitShadowedTypeParameterSharesParameterName.js Records JavaScript and corrected declaration output.

Review effort: Balanced

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 Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Declaration emit renames value references when a shadowed type parameter shares its parameter's name

2 participants