Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/typegpu/src/core/resolve/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ResolvedSnippet } from '../../data/snippet.ts';
import { bannedTokens, builtins } from '../../nameUtils.ts';
import { bannedTokens, builtins, templateEnumerants } from '../../nameUtils.ts';
import { $internal } from '../../shared/symbols.ts';
import { ShelllessRepository } from '../../tgsl/shellless.ts';
import type { TgpuLazy, TgpuSlot } from '../slot/slotTypes.ts';
Expand Down Expand Up @@ -36,7 +36,7 @@ class NamespaceImpl implements Namespace {
constructor(strategy: 'random' | 'strict') {
this[$internal] = {
strategy,
takenGlobalIdentifiers: new Set([...bannedTokens, ...builtins]),
takenGlobalIdentifiers: new Set([...bannedTokens, ...builtins, ...templateEnumerants]),
shelllessRepo: new ShelllessRepository(),
memoizedResolves: new WeakMap(),
memoizedLazy: new WeakMap(),
Expand Down
61 changes: 61 additions & 0 deletions packages/typegpu/src/nameUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,67 @@ export const bannedTokens = new Set([
'storage',
]);

/**
* Predeclared enumerants that appear as template parameters, e.g. `var<storage, read_write>` or
* `texture_storage_2d<rgba8unorm, write>`. A module-scope or local declaration with one of these names
* would shadow the enumerant, so a template using it would refer to the declaration instead.
* Unlike `bannedTokens`, these remain valid as struct member names, which never shadow anything.
*/
export const templateEnumerants = new Set([
// address spaces
'function',
'private',
'workgroup',
'uniform',
'storage',
Comment thread
pullfrog[bot] marked this conversation as resolved.
'immediate',
// access modes
'read',
'write',
'read_write',
// texel formats
'rgba8unorm',
'rgba8snorm',
'rgba8uint',
'rgba8sint',
'rgba16unorm',
'rgba16snorm',
'rgba16uint',
'rgba16sint',
'rgba16float',
'rg8unorm',
'rg8snorm',
'rg8uint',
'rg8sint',
'rg16unorm',
'rg16snorm',
'rg16uint',
'rg16sint',
'rg16float',
'r8unorm',
'r8snorm',
'r8uint',
'r8sint',
'r16unorm',
'r16snorm',
'r16uint',
'r16sint',
'r16float',
'r32uint',
'r32sint',
'r32float',
'rg32uint',
'rg32sint',
'rg32float',
'rgba32uint',
'rgba32sint',
'rgba32float',
'bgra8unorm',
'rgb10a2unorm',
'rgb10a2uint',
'rg11b10ufloat',
]);

export const builtins = new Set([
// constructors
'array',
Expand Down
46 changes: 46 additions & 0 deletions packages/typegpu/tests/namespace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,52 @@ import { tgpu, d } from 'typegpu';
import { it } from 'typegpu-testing-utility';

describe('tgpu.namespace', () => {
it('does not name a declaration after a template enumerant', ({ root }) => {
const counter = root.createMutable(d.u32).$name('read_write');
const scale = tgpu.privateVar(d.f32).$name('rgba8unorm');

const fn = () => {
'use gpu';
const write = counter.$ + 1;
scale.$ = d.f32(write);
};

expect(tgpu.resolve([fn])).toMatchInlineSnapshot(`
"@group(0) @binding(0) var<storage, read_write> read_write_1: u32;

var<private> rgba8unorm_1: f32;

fn fn_1() {
let write_1 = (read_write_1 + 1u);
rgba8unorm_1 = f32(write_1);
}"
`);
});

it('does not name an immediate after its own address space', () => {
const level = tgpu['~unstable'].immediateVar(d.f32).$name('immediate');
const fn = tgpu.fn([], d.f32)(() => level.$);

expect(tgpu.resolve([fn])).toMatchInlineSnapshot(`
"var<immediate> immediate_1: f32;

fn fn_1() -> f32 {
return immediate_1;
}"
`);
});

it('still accepts a template enumerant as a struct member name', () => {
const Access = d.struct({ read: d.u32, write: d.u32 });

expect(tgpu.resolve([Access])).toMatchInlineSnapshot(`
"struct Access {
read: u32,
write: u32,
}"
`);
});

it('defines direct dependencies only once', () => {
const Boid = d.struct({
pos: d.vec3f,
Expand Down