fix: reject unsigned unary negation - #2922
Conversation
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
std/operators.ts— reject unsignedneg—neg.signaturenow throwsWgslTypeErrorwhengetPrimitive(arg) === u32, so unary minus on unsigned scalars and vectors fails at resolution (before comptime folding and WGSL emission) instead of producing an implicit unsigned cast.wgslGenerator.test.ts— regression coverage — adds two exacttoThrowErrorMatchingInlineSnapshotcases covering scalar-onu32andstd.negonvec2u.
The fix is well-targeted: both syntax paths (-x via wgslGenerator.ts:172 and the std.neg export) dispatch through neg[$gpuCallable], so they all reach the new signature guard. getPrimitive unwraps vector/matrix composites to the singleton u32, making the identity check correct for vectors, and the message style matches the existing Unary operator ! error. The snapshots are exact-match and fail cleanly without the change, so the regression coverage is genuine.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Pull request overview
This PR tightens TGSL/WGSL type resolution to reject unary negation (-) on unsigned integer operands (per WGSL rules), ensuring the error is raised during resolution (before comptime folding and WGSL emission), and adds regression tests for both scalar - and std.neg paths.
Changes:
- Add early validation in
std.neg’s signature to throw aWgslTypeErrorfor unsupported unsigned negation. - Add WgslGenerator-focused tests asserting exact resolution error output for
u32scalar unary-andvec2upassed tostd.neg.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/typegpu/src/std/operators.ts | Adds signature-time validation for neg to reject unsigned operands with a WgslTypeError. |
| packages/typegpu/tests/tgsl/wgslGenerator.test.ts | Adds regression tests that assert resolution fails for -u32(...) and std.neg(vec2u). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| signature: (arg) => { | ||
| if (getPrimitive(arg) === u32) { | ||
| throw new WgslTypeError( | ||
| `Unary operator - requires a signed integer or floating-point operand. Got ${String(arg)}.`, | ||
| ); | ||
| } | ||
| return { | ||
| argTypes: [arg], | ||
| returnType: arg, | ||
| }; | ||
| }, |
There was a problem hiding this comment.
Thanks for flagging this. I traced both paths on the current head and they are already rejected before invalid WGSL can be emitted.
For u16, a focused resolver regression reaches the existing schema guard first and fails with 'u16 has no representation in WGSL'; it never reaches neg.signature. For bool and matrices, the public std.neg overloads come from cpuNeg(number | AnyNumericVecInstance), and TypeScript rejects both calls with TS2769. The signature callback is correspondingly typed through MapValueToDataType<Parameters>. Only an explicit unsafe cast can bypass that public contract.
The supported unsigned scalar/vector paths are u32 and vecNu; getPrimitive maps both to the same u32 singleton handled by this patch. I reran packages/typegpu/tests/tgsl/wgslGenerator.test.ts after the probes: 90/90 tests pass and the branch remains unchanged. I am keeping the fix scoped to the reachable unsigned WGSL operands from #2846.

Summary
u32neg.signatureso the error is raised before both comptime folding and WGSL emission-and unsigned-vectorstd.negpaths with exact resolution errorsWGSL does not define unary negation for unsigned integer scalars or vectors. This follows the maintainer direction in #2846 and avoids an implicit signed cast.
TDD evidence
RED: the scalar regression failed because
tgpu.resolve()emitted code instead of throwing.GREEN: the focused WgslGenerator suite passes 90/90 and both
u32andvec2unow fail at resolution with a descriptiveWgslTypeError.Verification
git diff --checkFixes #2846