Impr: Operator >>> support - #2784
Conversation
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.88, 1.74, 3.83, 6.24, 6.40, 12.06, 22.19, 24.07]
line [0.83, 1.71, 4.03, 5.43, 6.66, 10.29, 21.85, 21.63]
line [0.87, 1.64, 3.76, 5.37, 6.98, 9.16, 19.77, 23.13]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.28, 0.51, 0.70, 0.83, 1.12, 1.07, 1.30, 1.45]
line [0.33, 0.53, 0.70, 0.81, 1.08, 1.15, 1.29, 1.40]
line [0.25, 0.54, 0.67, 0.77, 1.04, 1.08, 1.37, 1.49]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.85, 1.92, 3.41, 5.97, 10.59, 22.74, 49.70, 103.74]
line [0.71, 2.01, 3.54, 5.96, 12.01, 24.07, 50.78, 103.68]
line [0.87, 1.85, 3.52, 5.84, 10.95, 23.34, 50.41, 101.22]
|
There was a problem hiding this comment.
Pull request overview
Adds support for JavaScript’s unsigned right shift operator (>>> / >>>=) in the TypeGPU TGSL → WGSL generator to match WGSL’s u32 shift semantics, and updates affected code to use it (avoiding CPU/GPU behavioral mismatches caused by JS >> being sign-preserving).
Changes:
- Extend WGSL generation to accept
>>>/>>>=, mapping them to WGSL>>/>>=, and validate/diagnose shift operand types (including deprecation warnings foru32 >>). - Fix CPU-side vector
u32right-shift behavior to use>>>(matching WGSL logical shift) and expand bit-shift test coverage. - Update examples/packages and ESLint rule to allow and prefer
>>>where unsigned right shift semantics are intended.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/typegpu/tests/std/numeric/bitShift.test.ts | Adds extensive coverage for shift typing, >>> support, and u32 >> deprecation warnings. |
| packages/typegpu/src/tgsl/wgslGenerator.ts | Implements >>> / >>>= support, operand validation, and deprecation warning for u32 LHS with >>. |
| packages/typegpu/src/std/operators.ts | Tightens std.bitShiftLeft/Right to vector-only usage and improves runtime argument error messaging. |
| packages/typegpu/src/data/wgslTypes.ts | Adds helpers to recognize integer32 scalars/vectors for generator validation. |
| packages/typegpu/src/data/vectorOps.ts | Fixes CPU vecNu right shift to use >>> (logical) instead of >> (arithmetic). |
| packages/typegpu-sort/src/bitonic/bitonicSort.ts | Switches to >>> for index computations intended to be unsigned shifts. |
| packages/typegpu-radiance-cascades/src/cascades.ts | Replaces unsigned shifts with >>> and ensures loop index type aligns with shifting needs. |
| packages/typegpu-noise/src/utils.ts | Removes prior std.isBeingTranspiled() branching for rotate-left and uses >>> consistently. |
| packages/typegpu-geometry/src/lines/polylineVariableWidth.ts | Uses >>> for unsigned index extraction. |
| packages/typegpu-geometry/src/lines/lineVariableWidth.ts | Uses >>> for unsigned index extraction. |
| packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts | Updates rule tests to no longer flag >>> / >>>= as unsupported. |
| packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts | Allows >>> / >>>= by removing them from unsupported operator lists. |
| apps/typegpu-docs/src/examples/simulation/game-of-life/shaders/bitpacked-compute.ts | Uses >>> for bitpacking shifts to match u32 behavior. |
| apps/typegpu-docs/src/examples/simulation/game-of-life/index.ts | Uses >>> when extracting bits from u32 packed textures. |
| apps/typegpu-docs/src/examples/rendering/radiance-cascades/index.ts | Updates unsigned shifts in the demo pipeline to >>>. |
| apps/typegpu-docs/src/examples/image-processing/selfie-segmentation/post-processing/kernels.ts | Replaces scalar std.bitShiftRight with >>> for correct unsigned coordinate extraction. |
| apps/typegpu-docs/src/examples/image-processing/selfie-segmentation/inference/video-preprocess.ts | Replaces scalar std.bitShiftRight with >>> for correct unsigned coordinate extraction. |
| apps/typegpu-docs/src/examples/image-processing/ascii-filter/index.ts | Uses >>> for unsigned bit extraction from u32 glyph bitfields. |
| apps/typegpu-docs/src/examples/geometry/lines-combinations/index.ts | Updates checker pattern computation to use >>> on u32 screen coordinates. |
| apps/typegpu-docs/src/examples/algorithms/genetic-racing/index.ts | Uses >>> for unpacking packed u32 values. |
| apps/typegpu-docs/src/examples/algorithms/bitonic-sort/index.ts | Uses >>> for extracting upper bits from an index seed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Caution
This PR introduces a type regression that breaks pnpm run test:types across dependent workspace packages.
Reviewed changes
This PR implements JavaScript >>>/>>>= operator support by mapping them to WGSL >>/>>= for unsigned left-hand sides; deprecates using >>/>>= with unsigned LHS; tightens codegen-time validation for all bit-shift operators; updates CPU-side unsigned-vector right shifts to use JS >>> semantics; migrates unsigned right-shift call sites; and removes >>>/>>>= from the ESLint unsupported-syntax list.
Type regression in infixOperators union
Removing scalar LHS overloads from cpuBitShiftLeft/cpuBitShiftRight leaves packages/typegpu/src/tgsl/infixDispatch.ts unable to call the infixOperators union members. tsc reports TS2349 in every workspace package that type-checks against typegpu.
The bit-shift functions can disallow scalar LHS while still exposing a DualFn signature compatible with the other infix operators, e.g. by keeping a scalar-scalar overload that throws at runtime or by adjusting infixDispatch.ts so it does not require a common callable signature across the union.
Technical details
# Type regression in infixOperators union
## Affected sites
- packages/typegpu/src/std/operators.ts:321 — `cpuBitShiftLeft` no longer has a scalar-scalar overload, so `DualFn<...>` contributes only vector signatures to `infixOperators`.
- packages/typegpu/src/std/operators.ts:351 — `cpuBitShiftRight` has the same issue.
- packages/typegpu/src/tgsl/infixDispatch.ts:64 — `opImpl(this as never, arg as never)` receives a union of `DualFn<...>` types with no common callable signature.
## Required outcome
- `pnpm run test:types` passes for the whole workspace.
## Suggested approach
- Restore a scalar-scalar overload on `cpuBitShiftLeft`/`cpuBitShiftRight` that throws at runtime, satisfying the union's common-callable-signature requirement without exposing working scalar support.
- Alternatively, constrain or widen the `InfixOperator`/`infixOperators` types so the runtime dispatch function does not require a callable common signature.Kimi K2 (free via Pullfrog for OSS) | 𝕏
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased (max 0.22%) | ❔ Unknown |
|---|---|---|---|
| 0 | 207 | 115 | 0 |
import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):
| Test | tsdown |
|---|---|
| tgpu_init.ts | 260.63 kB ( |
| tgpu_initFromDevice.ts | 260.10 kB ( |
| tgpu_resolve.ts | 166.00 kB ( |
| tgpu_resolveWithContext.ts | 165.94 kB ( |
| tgpu_bindGroupLayout.ts | 69.29 kB ( |
| tgpu_mutableAccessor.ts | 66.30 kB ( |
| tgpu_accessor.ts | 66.28 kB ( |
| tgpu_privateVar.ts | 65.63 kB ( |
| tgpu_workgroupVar.ts | 65.63 kB ( |
| tgpu_const.ts | 64.87 kB ( |
| tgpu_fn.ts | 38.45 kB ( |
| tgpu_fragmentFn.ts | 38.45 kB ( |
| tgpu_vertexFn.ts | 38.27 kB ( |
| tgpu_computeFn.ts | 37.97 kB ( |
| tgpu_vertexLayout.ts | 27.08 kB ( |
| tgpu_comptime.ts | 14.77 kB ( |
| tgpu_unroll.ts | 1.66 kB ( |
| tgpu_slot.ts | 1.54 kB ( |
| tgpu_lazy.ts | 1.19 kB ( |
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
|
pkg.pr.new packages benchmark commit |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
The latest commit (75f0744) addressed the prior type regression by widening the call signature in packages/typegpu/src/tgsl/infixDispatch.ts: opImpl is now cast to (lhs: unknown, rhs: unknown) => unknown before invocation, so the infixOperators union no longer needs a common callable signature across DualFn members.
I verified the fix by running pnpm run --filter typegpu test:types and the equivalent checks on the dependent packages previously reported as failing (@typegpu/color, @typegpu/gl, @typegpu/geometry, @typegpu/sdf, @typegpu/radiance-cascades, typegpu-testing-utility), all of which now pass. The bit-shift test suite (pnpm run --filter typegpu test -- bitShift.test.ts) and the ESLint plugin tests (pnpm run --filter eslint-plugin-typegpu test) also pass.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
| if (typeof lhs === 'number' && typeof rhs === 'number') { | ||
| return lhs >> rhs; | ||
| } | ||
| function cpuBitShiftRight<T extends AnyIntegerVecInstance>(lhs: T, rhs: number | vecIToVecU<T>): T { |
There was a problem hiding this comment.
Why don't we want std.bitShiftRight to support both scalars and vectors?
There was a problem hiding this comment.
in JS, we cannot distinguish if we received u32 or i32.
There was a problem hiding this comment.
We can support bitShiftRight. However, I deleted it for consistency.

Closes #2768.