Problem
When the generator knows what type an expression should have, it stores it in ctx.expectedType. Object and array literals use it to pick their struct/array type.
That value is never cleared for sub-expressions, so it also reaches places it was not meant for, for example the arguments of a function call:
const S = d.struct({ a: d.f32 });
const helper = (o: { b: number }) => {
'use gpu';
return S({ a: o.b });
};
const main = tgpu.fn([], S)(() => {
'use gpu';
return helper({ b: 1 });
});
tgpu.resolve([main]);
// Error: Missing property a in object literal for struct S
The { b: 1 } argument is checked against the return type of main (S), not against anything related to helper. The error message is confusing. If the shapes happen to match, the literal silently becomes an S.
Code: packages/typegpu/src/tgsl/wgslGenerator.ts. _typedExpression sets ctx.expectedType, and _expression reads it in three places (logical expressions, object literals, array literals), but nothing resets it for the children. Call arguments are generated with plain this._expression(arg) while the outer type is still set.
Proposed solution
Make the expected type apply only to the expression it was set for:
- At the start of
_expression, read ctx.expectedType into a local variable and set ctx.expectedType = undefined, so child expressions start with no expected type. Restore it at the end.
- The three places that read the expected type use the local variable.
- Where passing the type down is intended, pass it explicitly. This covers the two branches of a ternary (
c ? {…} : {…} inside a typed context).
_typedExpression stays the only way to set an expected type, so all existing typed contexts (struct fields, array items, return in shelled functions, strict function signatures) keep working.
Effect on resolution time
None. This is a correctness fix. With the fix applied, a synthetic shader with 1600 unrolled iterations resolved in 55–57 ms (median of 20), the same as main (56–57 ms) within noise.
Problem
When the generator knows what type an expression should have, it stores it in
ctx.expectedType. Object and array literals use it to pick their struct/array type.That value is never cleared for sub-expressions, so it also reaches places it was not meant for, for example the arguments of a function call:
The
{ b: 1 }argument is checked against the return type ofmain(S), not against anything related tohelper. The error message is confusing. If the shapes happen to match, the literal silently becomes anS.Code:
packages/typegpu/src/tgsl/wgslGenerator.ts._typedExpressionsetsctx.expectedType, and_expressionreads it in three places (logical expressions, object literals, array literals), but nothing resets it for the children. Call arguments are generated with plainthis._expression(arg)while the outer type is still set.Proposed solution
Make the expected type apply only to the expression it was set for:
_expression, readctx.expectedTypeinto a local variable and setctx.expectedType = undefined, so child expressions start with no expected type. Restore it at the end.c ? {…} : {…}inside a typed context)._typedExpressionstays the only way to set an expected type, so all existing typed contexts (struct fields, array items,returnin shelled functions, strict function signatures) keep working.Effect on resolution time
None. This is a correctness fix. With the fix applied, a synthetic shader with 1600 unrolled iterations resolved in 55–57 ms (median of 20), the same as
main(56–57 ms) within noise.