Skip to content

feat: Private property access#2594

Open
aleksanderkatan wants to merge 114 commits into
mainfrom
feat/private-property-access
Open

feat: Private property access#2594
aleksanderkatan wants to merge 114 commits into
mainfrom
feat/private-property-access

Conversation

@aleksanderkatan

@aleksanderkatan aleksanderkatan commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Blocked by #2425

Only the case with both "#prop" and #prop present breaks.

  it('...', () => {
    const cls = new (class {
      '#const' = tgpu.const(d.u32, 0);
      #const = tgpu.const(d.u32, 1);

      fn = () => {
        'use gpu';
        const a = this['#const'].$;
        const b = this.#const.$;
      };
    })();

    expect(tgpu.resolve([cls.fn])).toMatchInlineSnapshot(`
      "const item: u32 = 0u;

      fn fn_1() {
        const a = item;
        const b = item;
      }"
    `);
  });

@aleksanderkatan aleksanderkatan changed the base branch from main to feat/expand-property-access-in-externals June 9, 2026 08:39
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

pkg.pr.new

packages
Ready to be installed by your favorite package manager ⬇️

https://pkg.pr.new/software-mansion/TypeGPU/eslint-plugin-typegpu@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/tgpu-gen@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/tinyest-for-wgsl@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/typegpu@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/cli@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/color@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/gl@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/noise@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/radiance-cascades@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/react@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/sdf@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/@typegpu/three@a1c4c89450b7df107a86ca5e5791f74032bfae33
https://pkg.pr.new/software-mansion/TypeGPU/unplugin-typegpu@a1c4c89450b7df107a86ca5e5791f74032bfae33

benchmark
view benchmark

commit
view commit

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Bundle size comparison (import * as ... in PR vs import * as ... in target):

🟢 Decreased ➖ Unchanged 🔴 Increased ❔ Unknown
0 321 0 0

import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):

Test tsdown
tgpu_init.ts 255.87 kB ($${\color{green}-3.2\%}$$)
tgpu_initFromDevice.ts 255.36 kB ($${\color{green}-3.4\%}$$)
tgpu_resolve.ts 161.34 kB ($${\color{green}-38.9\%}$$)
tgpu_resolveWithContext.ts 161.28 kB ($${\color{green}-39.0\%}$$)
tgpu_bindGroupLayout.ts 68.92 kB ($${\color{green}-73.9\%}$$)
tgpu_mutableAccessor.ts 65.91 kB ($${\color{green}-75.1\%}$$)
tgpu_accessor.ts 65.90 kB ($${\color{green}-75.1\%}$$)
tgpu_privateVar.ts 65.27 kB ($${\color{green}-75.3\%}$$)
tgpu_workgroupVar.ts 65.27 kB ($${\color{green}-75.3\%}$$)
tgpu_const.ts 64.52 kB ($${\color{green}-75.6\%}$$)
tgpu_fn.ts 37.98 kB ($${\color{green}-85.6\%}$$)
tgpu_fragmentFn.ts 37.88 kB ($${\color{green}-85.7\%}$$)
tgpu_vertexFn.ts 37.70 kB ($${\color{green}-85.7\%}$$)
tgpu_computeFn.ts 37.40 kB ($${\color{green}-85.8\%}$$)
tgpu_vertexLayout.ts 26.63 kB ($${\color{green}-89.9\%}$$)
tgpu_comptime.ts 14.43 kB ($${\color{green}-94.5\%}$$)
tgpu_unroll.ts 2.60 kB ($${\color{green}-99.0\%}$$)
tgpu_slot.ts 1.54 kB ($${\color{green}-99.4\%}$$)
tgpu_lazy.ts 1.19 kB ($${\color{green}-99.5\%}$$)

If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.

@aleksanderkatan

Copy link
Copy Markdown
Contributor Author

@pullfrog review

@pullfrog pullfrog Bot 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.

Important

The Rollup externals test isn't actually testing the Rollup path, and the combined public/private #prop case silently resolves the wrong resource. Both need addressing before merge.

Reviewed changes — this PR enables JavaScript private class properties as TypeGPU externals, adds auto-naming for ClassPrivateProperty, and removes the lint rule that unconditionally banned private identifiers.

  • Lift the blanket PrivateIdentifier lint ban in packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts so this.#prop access is allowed.
  • Track #prop chains in packages/tinyest-for-wgsl/src/externals.ts by handling both Babel PrivateName and acorn PrivateIdentifier.
  • Auto-name private class fields in packages/unplugin-typegpu/src/core/common.ts via a new ClassPrivateProperty visitor and matching extractLabelledExpression branch.
  • Add test coverage for private property access across tinyest-for-wgsl, typegpu, and unplugin-typegpu.

Collision between private #prop and string-key "#prop"

A class that defines both a public '#prop' and a private #prop currently routes both this['#prop'].$ and this.#prop.$ through the same this.#prop external key. The runtime object-based external replacement then resolves the public property value, so the private field value is silently dropped. This matches the limitation noted in the PR body; please either fix the key encoding or add a tracking issue/TODO so the limitation is visible to users and future maintainers.

Technical details
# Collision between private `#prop` and string-key `"#prop"`

## Affected sites
- packages/tinyest-for-wgsl/src/externals.ts:32-35 — private names are encoded as `this.#prop`, identical to the runtime object-property replacement path used for `this["#prop"]`.
- packages/typegpu/src/core/resolve/externals.ts:104-129 — object external replacement uses `externalName\\.(?<prop>...)` and matches `this.#prop` for `this` externals.

## Required outcome
- `this.#prop` (private field) and `this["#prop"]` (public string key) resolve to distinct resources when both are present.

## Suggested approach
Consider encoding private names with a distinct prefix or namespace (e.g., `this.private.#prop`) and teaching the resolver to map that prefix back to the private-field accessor. Alternatively, document the limitation and add a failing/todo test linking to an issue.

## Open questions for the human
- Is the combined case expected to be fixed in this PR, or is there a follow-up issue already planned? Please link it in a code comment so the next agent doesn't re-discover it.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread packages/unplugin-typegpu/test/nested-externals.test.ts Outdated
Base automatically changed from feat/expand-property-access-in-externals to main July 13, 2026 13:53
@aleksanderkatan aleksanderkatan marked this pull request as ready for review July 13, 2026 16:29
@aleksanderkatan

Copy link
Copy Markdown
Contributor Author

@reczkok @iwoplaza @cieplypolar this is reviewable again

@pullfrog pullfrog Bot 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.

\u2139\ufe0f No critical issues \u2014 minor suggestions inline.

Reviewed changes \u2014 Adds support for accessing class private properties (this.#prop) from 'use gpu' functions by teaching external-chain extraction and auto-naming to recognize private property AST nodes.

  • Removes the PrivateIdentifier ban in noUnsupportedSyntax.
  • Extends tryFindExternalChain to build chain strings like this.#prop.
  • Extends unplugin-typegpu auto-naming to ClassPrivateProperty nodes and assignments to private properties.
  • Adds parser, resolution, auto-naming, and nested-externals tests for private property access.

Pullfrog  | Fix it ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@pullfrog

pullfrog Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

One small test-coverage suggestion: the PR body calls out the case where both a public string property named "#prop" (this['#prop']) and a private property #prop exist in the same class. The new tests cover each in isolation (packages/typegpu/tests/externalPropAccess.test.ts lines 95 and 135), but a single regression test with both present would guard the exact collision scenario this PR fixes.

Pullfrog  | View workflow run | via Pullfrog | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@iwoplaza iwoplaza left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks great! 💜 :shipit:

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.

feat: Support private property access in TypeGPU functions

3 participants