Repository navigation
Reuse this-independent interface member instantiations - #64924
Илия (777genius) wants to merge 1 commit into
Conversation
Avoid repeated synthetic-this member instantiation for proved completed nongeneric interfaces. Preserve captured and polymorphic this, generic interfaces, and unresolved bases. Refs microsoft#63555
|
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
There was a problem hiding this comment.
🔵 Needs a closer look
Changes to shared type-reference identity and recursive resolution invariants warrant compiler-maintainer review despite no confirmed defects.
No open issues 🎉
What changed in this PR
This PR reduces inherited-member instantiation costs in the native TypeScript checker by reusing synthetic this arguments when interface members are proven independent of them. It complements, but does not include, the base-search optimization in #64737.
Changes:
- Adds conservative independence checks before reusing interface member instantiations.
- Tracks mapped-member finalization to exclude incomplete resolution state.
- Adds regression coverage and type, symbol, and JavaScript baselines.
| File | Description |
|---|---|
tsc/testdata/tests/cases/compiler/thisIndependentInterfaceMembers.ts |
Tests this preservation, generics, recursion, errors, and concrete members. |
tsc/testdata/baselines/reference/compiler/thisIndependentInterfaceMembers.types |
Records expected inferred types. |
tsc/testdata/baselines/reference/compiler/thisIndependentInterfaceMembers.symbols |
Records expected symbol bindings. |
tsc/testdata/baselines/reference/compiler/thisIndependentInterfaceMembers.js |
Records expected JavaScript output. |
tsc/internal/checker/types.go |
Adds independence and mapped-member finalization flags. |
tsc/internal/checker/checker.go |
Certifies independence and reuses eligible synthetic this arguments. |
Review effort: Balanced
|
@microsoft-github-policy-service agree |
|
Are there any real world codebases that hit this? Note how none of our benchmarks were affected by that other PR |
Fixes #64925.
Analysis
Inherited interfaces with concrete mapped members can repeatedly materialize those members with descendant synthetic
thisarguments, even when the members do not depend on that argument. The package-free N200 reproduction below isolates that allocation cost.This is separate from the base-search cost in #63555 and Mitch Fultz's #64737. That change is excluded from this PR and is used only as a separately attributed comparison input.
Fix
Record independence only for completed, nongeneric interfaces with nonempty all-interface declarations, no declared
this, and suitable completed ancestry. Classes, mixed class/interface symbols, outer/local generics and unproved bases retain the existing path.A mapped base must retain identity, have a finalized member table and no recorded recursive mapped-property error, and satisfy the existing
instantiateTypeWithAliasno-instantiation predicate, including alias arguments. Property types remain lazy. For proved references, reuse the target's own syntheticthisthrough the existing instantiation path.The focused test covers captured/foreign/fluent
this, merged and generic declarations, recursive lookup, mapped errors, conflicts, and call/index members. All three baselines were generated with the unmodified selected checker and match the candidate. Production changes are +35/-1 in two Go files; the remaining changes are the test and its generated baselines.Copilot Checklist
I successfully ran the applicable command on the published candidate, and it completed without error:
npx hereby validatenpx hereby validate --api— N/A: no JavaScript API implementation changes. API tests also passed separately throughtest:alland the package test command.PR template checklist
mainrevision98add1bbed1c814e97457587c2da407dc3f78330.npx hereby testnpx hereby lintnpx hereby check:formatValidation
Linux x64; Go 1.27.2, Node 24.20.0, pinned npm 11.19.1. The complete CONTRIBUTING before-PR command list passed, including generation/build, one full
test:all, package builds/tests and Go tidy/workspace checks. The compiler/module suite reported 168,194 tests and 2,139 skips. The additionalvalidaterun passed with zero lint issues and left the six-file patch unchanged.CLA passed. Upstream CI and CodeQL await maintainer approval and have not executed.
Performance
Exact inputs:
98add1bbed1c814e97457587c2da407dc3f78330.d29324e35ff691aa6307645f2fce56b0c62a030c.3200b90a617bcf9ad26543b347cabad8ff0dad14, PR baseaa8149273b23401f0a79a5f0384c42de51888693.Five alternating-order rounds, fresh processes,
--singleThreaded --extendedDiagnostics --noEmit;GOMAXPROCS=4,GOMEMLIMIT=4GiB. Median compiler-reported values for mapped N200:All 60 runs succeeded, with matching diagnostics across variants. The inline control with #64737/stack checked in 0.139/0.146 s with equal type/instantiation counts. Five cold runs per variant of one owner compiler fixture gave base/PR medians 0.898/0.885 s and #64737/stack 0.907/0.933 s; each used an initially absent unique build-info file. These are local samples, not representative-project performance guarantees.
Package-free reproduction generator
Requirements: Go 1.27 and Node 24. From each selected compiler checkout, build an embedded-libraries executable with:
Save the generator below as
generate-repro.mtsin an empty directory and runnode generate-repro.mts mapped. Compile its output with/absolute/path/compiler --project tsconfig.json --singleThreaded --extendedDiagnostics --noEmit. Run the generator withinlinefor the control. The generated witness sources match the measured inputs byte-for-byte.The current-base private two-component stack also passed the unchanged N1000 compiler/runtime growth run in 17.55 s aggregate. This is supplemental consumer evidence; it does not establish standalone full-workload success or supported compiler adoption.
Related work
Open #64915 changes the same member-resolution path to lazy shared layouts. This patch targets the selected current
main; it does not apply unchanged to that proposal. If #64915 lands first, the proof placement and performance benefit need re-evaluation on its lazy layout before integration. A separate five-round N200 comparison of exact #64915 head10ba045ea637cf10d59aef3e1a107b8f50464db3plus #64737 retained 70,507 types and used 64,441 K, versus 30,307 types and 47,833 K for current-main + #64737 + this PR. All 40 mapped/inline runs had empty diagnostics. This comparison does not establish the benefit of combining this patch with lazy layouts. #64873 separately avoids resolving mapped members for signature-only queries.AI assistance
Codex assisted with investigating this specific Get Modular scaling problem, implementing the patch/tests, validation and review.