Skip to content

fix: reject unsigned unary negation - #2922

Open
huytdps13400 wants to merge 1 commit into
software-mansion:mainfrom
huytdps13400:fix/2846-reject-unsigned-negation
Open

fix: reject unsigned unary negation#2922
huytdps13400 wants to merge 1 commit into
software-mansion:mainfrom
huytdps13400:fix/2846-reject-unsigned-negation

Conversation

@huytdps13400

Copy link
Copy Markdown

Summary

  • reject unary negation when the operand primitive is u32
  • validate in neg.signature so the error is raised before both comptime folding and WGSL emission
  • cover scalar unary - and unsigned-vector std.neg paths with exact resolution errors

WGSL 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 u32 and vec2u now fail at resolution with a descriptive WgslTypeError.

Verification

  • package typecheck passes
  • changed files pass oxlint and oxfmt
  • source TypeGPU suite: 176 files, 2,364 tests pass
  • built TypeGPU suite: 144 files, 1,941 tests pass
  • circular dependency check passes
  • git diff --check

Fixes #2846

Copilot AI lite review requested due to automatic review settings August 26, 2026 08:55

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

✅ No new issues found.

Reviewed changes

  • std/operators.ts — reject unsigned negneg.signature now throws WgslTypeError when getPrimitive(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 exact toThrowErrorMatchingInlineSnapshot cases covering scalar - on u32 and std.neg on vec2u.

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.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

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.

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 a WgslTypeError for unsupported unsigned negation.
  • Add WgslGenerator-focused tests asserting exact resolution error output for u32 scalar unary - and vec2u passed to std.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.

Comment on lines +250 to +260
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,
};
},

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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.

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.

bug: Unary - is not supported for u32 values

2 participants