Skip to content

Commit f71969f

Browse files
fix: Disallow references in arrays (#1990)
1 parent f9a4402 commit f71969f

3 files changed

Lines changed: 65 additions & 5 deletions

File tree

apps/typegpu-docs/src/examples/rendering/cubemap-reflection/icosphere.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export class IcosphereGenerator {
164164
1,
165165
);
166166

167-
const newVertices = [
167+
const newVertices = d.arrayOf(d.vec4f, 12)([
168168
// Triangle A: [v1, v12, v31]
169169
v1,
170170
v12,
@@ -181,7 +181,7 @@ export class IcosphereGenerator {
181181
v12,
182182
v23,
183183
v31,
184-
];
184+
]);
185185

186186
const baseIndexNext = triangleIndex * 12;
187187
for (let i = d.u32(0); i < 12; i++) {

packages/typegpu/src/tgsl/wgslGenerator.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,24 @@ ${this.ctx.pre}}`;
720720
}
721721
} else {
722722
// The array is not typed, so we try to guess the types.
723-
const valuesSnippets = valueNodes.map((value) =>
724-
this.expression(value as tinyest.Expression)
725-
);
723+
const valuesSnippets = valueNodes.map((value) => {
724+
const snippet = this.expression(value as tinyest.Expression);
725+
// We check if there are no references among the elements
726+
if (
727+
(snippet.origin === 'argument' &&
728+
!wgsl.isNaturallyEphemeral(snippet.dataType)) ||
729+
!isEphemeralSnippet(snippet)
730+
) {
731+
const snippetStr =
732+
this.ctx.resolve(snippet.value, snippet.dataType).value;
733+
const snippetType =
734+
this.ctx.resolve(concretize(snippet.dataType as AnyData)).value;
735+
throw new WgslTypeError(
736+
`'${snippetStr}' reference cannot be used in an array constructor.\n-----\nTry '${snippetType}(${snippetStr})' or 'arrayOf(${snippetType}, count)([...])' to copy the value instead.\n-----`,
737+
);
738+
}
739+
return snippet;
740+
});
726741

727742
if (valuesSnippets.length === 0) {
728743
throw new WgslTypeError(

packages/typegpu/tests/array.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,51 @@ describe('array', () => {
329329
}"
330330
`);
331331
});
332+
333+
it('throws when using refs in arrays', () => {
334+
const foo = tgpu.fn([])(() => {
335+
const myVec = d.vec2f(1, 2);
336+
const result = [d.vec2f(3, 4), myVec];
337+
});
338+
339+
expect(() => tgpu.resolve([foo])).toThrowErrorMatchingInlineSnapshot(`
340+
[Error: Resolution of the following tree failed:
341+
- <root>
342+
- fn:foo: 'myVec' reference cannot be used in an array constructor.
343+
-----
344+
Try 'vec2f(myVec)' or 'arrayOf(vec2f, count)([...])' to copy the value instead.
345+
-----]
346+
`);
347+
});
348+
349+
it('throws when using argument refs in arrays', () => {
350+
const foo = tgpu.fn([d.vec2f])((myVec) => {
351+
const result = [d.vec2f(3, 4), myVec];
352+
});
353+
354+
expect(() => tgpu.resolve([foo])).toThrowErrorMatchingInlineSnapshot(`
355+
[Error: Resolution of the following tree failed:
356+
- <root>
357+
- fn:foo: 'myVec' reference cannot be used in an array constructor.
358+
-----
359+
Try 'vec2f(myVec)' or 'arrayOf(vec2f, count)([...])' to copy the value instead.
360+
-----]
361+
`);
362+
});
363+
364+
it('allows using ephemeral refs in arrays', () => {
365+
const foo = tgpu.fn([d.u32])((n) => {
366+
const m = d.u32(1);
367+
const result = [1, n, m];
368+
});
369+
370+
expect(tgpu.resolve([foo])).toMatchInlineSnapshot(`
371+
"fn foo(n: u32) {
372+
const m = 1u;
373+
var result = array<u32, 3>(1u, n, m);
374+
}"
375+
`);
376+
});
332377
});
333378

334379
describe('array.length', () => {

0 commit comments

Comments
 (0)