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
10 changes: 1 addition & 9 deletions packages/typegpu/src/resolutionCtx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -970,14 +970,6 @@ export class ResolutionCtxImpl implements ResolutionCtx {
);
}

if (Array.isArray(item)) {
return snip(
stitch`array(${item.map((element) => this.resolve(element))})`,
UnknownData,
/* origin */ 'runtime',
) as ResolvedSnippet;
}

if (schema && isWgslStruct(schema)) {
return snip(
stitch`${this.resolve(schema)}(${Object.entries(schema.propTypes).map(([key, propType]) =>
Expand All @@ -989,7 +981,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
}

throw new WgslTypeError(
`Value ${item} (as json: ${safeStringify(item)}) is not resolvable${
`Value ${safeStringify(item)} is not resolvable${
schema ? ` to type ${safeStringify(schema)}` : ''
}`,
);
Expand Down
4 changes: 4 additions & 0 deletions packages/typegpu/src/shared/stringify.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { isMatInstance, isVecInstance } from '../data/wgslTypes.ts';

export function safeStringify(item: unknown): string {
if (Array.isArray(item)) {
return `[${item.map(safeStringify).join(', ')}]`;
}
Comment on lines +4 to +6
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

safeStringify now recursively stringifies arrays without any cycle detection. Self-referential arrays (or arrays containing references that lead back to the same array) will cause infinite recursion / stack overflow while formatting an error message. Consider adding cycle detection (e.g., a WeakSet/Set of visited objects passed through recursion) and a fallback string (like "[<circular>]"), and optionally a max depth/length to keep error messages bounded.

Copilot uses AI. Check for mistakes.

const asString = String(item);
if (asString !== '[object Object]') {
return asString;
Expand Down
27 changes: 23 additions & 4 deletions packages/typegpu/tests/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,18 +193,21 @@ describe('array', () => {
it('generates correct code when array clone is used', () => {
const ArraySchema = d.arrayOf(d.u32, 1);

const f = (arr: d.Infer<typeof ArraySchema>) => {
function f(arr: d.InferGPU<typeof ArraySchema>) {
'use gpu';
const clone = ArraySchema(arr);
};
}

const testFn = () => {
const external = [3];

function testFn() {
'use gpu';
const myArray = ArraySchema([d.u32(10)]);
const myClone = ArraySchema(myArray);
const myExternal = ArraySchema(external);
f(myArray);
return;
};
}

expect(tgpu.resolve([testFn])).toMatchInlineSnapshot(`
"fn f(arr: array<u32, 1>) {
Expand All @@ -214,6 +217,7 @@ describe('array', () => {
fn testFn() {
var myArray = array<u32, 1>(10u);
var myClone = myArray;
var myExternal = array<u32, 1>(3u);
f(myArray);
return;
}"
Expand Down Expand Up @@ -538,6 +542,21 @@ describe('array', () => {
}"
`);
});

it('throws when trying to resolve an untyped external array', () => {
const arr = [1, 2, 3];
function main() {
'use gpu';
arr;
Comment thread
iwoplaza marked this conversation as resolved.
}

expect(() => tgpu.resolve([main])).toThrowErrorMatchingInlineSnapshot(`
[Error: Resolution of the following tree failed:
- <root>
- fn*:main
- fn*:main(): Value [1, 2, 3] is not resolvable]
`);
});
});

describe('array.length', () => {
Expand Down
Loading