diff --git a/packages/typegpu/src/core/resolve/externals.ts b/packages/typegpu/src/core/resolve/externals.ts index f95dc67c6f..ab3c885d0c 100644 --- a/packages/typegpu/src/core/resolve/externals.ts +++ b/packages/typegpu/src/core/resolve/externals.ts @@ -1,6 +1,6 @@ import { isLooseData } from '../../data/dataTypes.ts'; import { isWgslStruct } from '../../data/wgslTypes.ts'; -import { getName, hasTinyestMetadata, setName } from '../../shared/meta.ts'; +import { getName, hasTinyestMetadata, isNamable, setName } from '../../shared/meta.ts'; import { isWgsl, type ResolutionCtx } from '../../types.ts'; /** @@ -42,15 +42,6 @@ export function mergeExternals(existing: ExternalMap, newExternals: ExternalMap) } else { existing[key] = value; } - - // Giving name to external value, if it does not already have one. - if ( - value && - (typeof value === 'object' || typeof value === 'function') && - getName(value) === undefined - ) { - setName(value, key); - } } } @@ -115,6 +106,9 @@ export function replaceExternalsInWgsl( } if (isResolvable(external)) { + if (isNamable(external) && getName(external) === undefined) { + setName(external, externalName.split('.').at(-1) as string); + } return acc.replaceAll(externalRegex, ctx.resolve(external).value); } diff --git a/packages/typegpu/src/core/root/init.ts b/packages/typegpu/src/core/root/init.ts index 075ac5e36a..3fb6af3bff 100644 --- a/packages/typegpu/src/core/root/init.ts +++ b/packages/typegpu/src/core/root/init.ts @@ -95,7 +95,7 @@ import { vec3f, vec3u } from '../../data/vector.ts'; import { u32 } from '../../data/numeric.ts'; import { ceil } from '../../std/numeric.ts'; import { allEq } from '../../std/boolean.ts'; -import { setName } from '../../shared/meta.ts'; +import { getName, setName } from '../../shared/meta.ts'; /** * Changes the given array to a vec of 3 numbers, filling missing values with 1. @@ -259,6 +259,9 @@ class WithBindingImpl implements WithBinding { const workgroupSize = workgroupSizeConfigs[callback.length] as v3u; const wrappedCallback = fn([u32, u32, u32])(callback as (...args: number[]) => void); + if (getName(wrappedCallback) === undefined) { + wrappedCallback.$name('wrappedCallback'); + } const sizeUniform = root.createUniform(vec3u); diff --git a/packages/typegpu/src/resolutionCtx.ts b/packages/typegpu/src/resolutionCtx.ts index f95399c67a..3956e0ecb6 100644 --- a/packages/typegpu/src/resolutionCtx.ts +++ b/packages/typegpu/src/resolutionCtx.ts @@ -51,7 +51,7 @@ import type { } from './types.ts'; import { CodegenState, isSelfResolvable, NormalState } from './types.ts'; import type { WgslEnableExtension } from './wgslExtensions.ts'; -import { getName, hasTinyestMetadata, setName } from './shared/meta.ts'; +import { getName, hasTinyestMetadata, isNamable, setName } from './shared/meta.ts'; import { FuncParameterType } from 'tinyest'; import { accessProp } from './tgsl/accessProp.ts'; import { createIoSchema } from './core/function/ioSchema.ts'; @@ -197,6 +197,9 @@ class ItemStateStackImpl implements ItemStateStack { } const external = layer.externalMap[id]; + if (isNamable(external) && getName(external) === undefined) { + setName(external, id); + } if (external !== undefined && external !== null) { return coerceToSnippet(external); diff --git a/packages/typegpu/src/tgsl/accessProp.ts b/packages/typegpu/src/tgsl/accessProp.ts index 147eddd2a7..b3cfc1fb2e 100644 --- a/packages/typegpu/src/tgsl/accessProp.ts +++ b/packages/typegpu/src/tgsl/accessProp.ts @@ -34,6 +34,7 @@ import { isKnownAtComptime } from '../types.ts'; import { coerceToSnippet, numericLiteralToSnippet } from './generationHelpers.ts'; import { InfixDispatch, infixOperators, type InfixOperatorName } from './infixDispatch.ts'; import { accessStructProp } from './accessStructProp.ts'; +import { getName, isNamable, setName } from '../shared/meta.ts'; const infixKinds = [ 'vec2f', @@ -205,7 +206,11 @@ export function accessProp(target: Snippet, propName: string): Snippet | undefin if (isKnownAtComptime(target) || target.dataType === UnknownData) { // oxlint-disable-next-line typescript/no-explicit-any -- we either know exactly what it is, or have no idea at all - return coerceToSnippet((target.value as any)[propName]); + const prop = (target.value as any)[propName]; + if (isNamable(prop) && getName(prop) === undefined) { + setName(prop, propName); + } + return coerceToSnippet(prop); } return undefined; diff --git a/packages/typegpu/tests/rawFn.test.ts b/packages/typegpu/tests/rawFn.test.ts index b63036de3b..19e310bfc2 100644 --- a/packages/typegpu/tests/rawFn.test.ts +++ b/packages/typegpu/tests/rawFn.test.ts @@ -539,6 +539,42 @@ describe('tgpu.fn with raw wgsl and missing types', () => { }" `); }); + + it('names resolved externals', () => { + const c1 = (() => tgpu.const(d.vec2u, d.vec2u(1)))(); // unnamed + const c2 = (() => tgpu.const(d.vec2u, d.vec2u(2)))(); // unnamed + const c3 = (() => tgpu.const(d.vec2u, d.vec2u(3)))(); // unnamed + const fn = tgpu.fn([])`() { + let a = n1; + let b = ext.n2; + let c = ext.n3.x; +}`.$uses({ + n1: c1, + ext: { n2: c2, n3: c3 }, + }); + + expect(tgpu.resolve([fn])).toMatchInlineSnapshot(` + "const n1: vec2u = vec2u(1); + + const n2: vec2u = vec2u(2); + + const n3: vec2u = vec2u(3); + + fn fn_1() { + let a = n1; + let b = n2; + let c = n3.x; + }" + `); + }); + + it("resolved externals's names stay the same", () => { + const c1 = (() => tgpu.const(d.vec2u, d.vec2u(1)))(); // unnamed + tgpu.resolve([tgpu.fn([])`() { let a = myConst; }`.$uses({ myConst: c1 })]); + tgpu.resolve([tgpu.fn([])`() { let a = otherName; }`.$uses({ otherName: c1 })]); + + expect(getName(c1)).toMatchInlineSnapshot(`"myConst"`); + }); }); describe('tgpu.computeFn with raw string WGSL implementation', () => { diff --git a/packages/typegpu/tests/tgslFn.test.ts b/packages/typegpu/tests/tgslFn.test.ts index ba4d5165f2..85529afe89 100644 --- a/packages/typegpu/tests/tgslFn.test.ts +++ b/packages/typegpu/tests/tgslFn.test.ts @@ -1077,4 +1077,36 @@ describe('tgsl fn when using plugin', () => { }" `); }); + + it('names used externals', () => { + const myConst = (() => tgpu.const(d.u32, 1))(); // unnamed + const fn = () => { + 'use gpu'; + return myConst.$; + }; + + expect(tgpu.resolve([fn])).toMatchInlineSnapshot(` + "const myConst: u32 = 1u; + + fn fn_1() -> u32 { + return myConst; + }" + `); + }); + + it('names used nested externals', () => { + const EXT = { myConst: (() => tgpu.const(d.u32, 1))() /* unnamed */ }; + const fn = () => { + 'use gpu'; + return EXT.myConst.$; + }; + + expect(tgpu.resolve([fn])).toMatchInlineSnapshot(` + "const myConst: u32 = 1u; + + fn fn_1() -> u32 { + return myConst; + }" + `); + }); });