Skip to content

Commit 821e301

Browse files
fix: Remove redundant .with slot calls & chore: Cleanup ItemStateStack (#1853)
1 parent f6cd3b7 commit 821e301

File tree

7 files changed

+66
-51
lines changed

7 files changed

+66
-51
lines changed

apps/typegpu-docs/src/examples/simulation/fluid-double-buffering/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ function makePipelines(
454454
outputGridMutable: TgpuBufferMutable<GridData>,
455455
) {
456456
const initWorldPipeline = root['~unstable']
457-
.with(inputGridSlot, outputGridMutable)
458457
.with(outputGridSlot, outputGridMutable)
459458
.createGuardedComputePipeline((xu, yu) => {
460459
'use gpu';

packages/typegpu/src/core/function/tgpuFn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ function createBoundFunction<ImplSchema extends AnyFn>(
291291
slot: TgpuSlot<unknown> | TgpuAccessor,
292292
value: unknown,
293293
): TgpuFn<ImplSchema> {
294-
return createBoundFunction(fn, [
294+
return createBoundFunction(innerFn, [
295295
...pairs,
296296
[isAccessor(slot) ? slot.slot : slot, value],
297297
]);

packages/typegpu/src/resolutionCtx.ts

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import type {
7676
ItemLayer,
7777
ItemStateStack,
7878
ResolutionCtx,
79+
StackLayer,
7980
TgpuShaderStage,
8081
Wgsl,
8182
} from './types.ts';
@@ -103,23 +104,8 @@ export type ResolutionCtxImplOptions = {
103104
readonly namespace: Namespace;
104105
};
105106

106-
type SlotBindingLayer = {
107-
type: 'slotBinding';
108-
bindingMap: WeakMap<TgpuSlot<unknown>, unknown>;
109-
};
110-
111-
type BlockScopeLayer = {
112-
type: 'blockScope';
113-
declarations: Map<string, Snippet>;
114-
};
115-
116107
class ItemStateStackImpl implements ItemStateStack {
117-
private _stack: (
118-
| ItemLayer
119-
| SlotBindingLayer
120-
| FunctionScopeLayer
121-
| BlockScopeLayer
122-
)[] = [];
108+
private _stack: StackLayer[] = [];
123109
private _itemDepth = 0;
124110

125111
get itemDepth(): number {
@@ -146,21 +132,13 @@ class ItemStateStackImpl implements ItemStateStack {
146132
});
147133
}
148134

149-
popItem() {
150-
this.pop('item');
151-
}
152-
153135
pushSlotBindings(pairs: SlotValuePair<unknown>[]) {
154136
this._stack.push({
155137
type: 'slotBinding',
156138
bindingMap: new WeakMap(pairs),
157139
});
158140
}
159141

160-
popSlotBindings() {
161-
this.pop('slotBinding');
162-
}
163-
164142
pushFunctionScope(
165143
functionType: 'normal' | TgpuShaderStage,
166144
args: Snippet[],
@@ -182,31 +160,26 @@ class ItemStateStackImpl implements ItemStateStack {
182160
return scope;
183161
}
184162

185-
popFunctionScope() {
186-
this.pop('functionScope');
187-
}
188-
189163
pushBlockScope() {
190164
this._stack.push({
191165
type: 'blockScope',
192166
declarations: new Map(),
193167
});
194168
}
195169

196-
popBlockScope() {
197-
this.pop('blockScope');
198-
}
199-
200-
pop(type?: (typeof this._stack)[number]['type']) {
170+
pop<T extends StackLayer['type']>(type: T): Extract<StackLayer, { type: T }>;
171+
pop(): StackLayer | undefined;
172+
pop(type?: StackLayer['type']) {
201173
const layer = this._stack[this._stack.length - 1];
202174
if (!layer || (type && layer.type !== type)) {
203175
throw new Error(`Internal error, expected a ${type} layer to be on top.`);
204176
}
205177

206-
this._stack.pop();
178+
const poppedValue = this._stack.pop();
207179
if (type === 'item') {
208180
this._itemDepth--;
209181
}
182+
return poppedValue;
210183
}
211184

212185
readSlot<T>(slot: TgpuSlot<T>): T | undefined {
@@ -452,7 +425,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
452425
}
453426

454427
popBlockScope() {
455-
this._itemStateStack.popBlockScope();
428+
this._itemStateStack.pop('blockScope');
456429
}
457430

458431
generateLog(op: string, args: Snippet[]): Snippet {
@@ -560,7 +533,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
560533
};
561534
} finally {
562535
if (fnScopePushed) {
563-
this._itemStateStack.popFunctionScope();
536+
this._itemStateStack.pop('functionScope');
564537
}
565538
this.#namespaceInternal.nameRegistry.popFunctionScope();
566539
}
@@ -612,7 +585,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
612585
try {
613586
return callback();
614587
} finally {
615-
this._itemStateStack.popSlotBindings();
588+
this._itemStateStack.pop('slotBinding');
616589
}
617590
}
618591

@@ -700,7 +673,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
700673

701674
throw new ResolutionError(err, [derived]);
702675
} finally {
703-
this._itemStateStack.popItem();
676+
this._itemStateStack.pop('item');
704677
}
705678
}
706679

@@ -772,7 +745,7 @@ export class ResolutionCtxImpl implements ResolutionCtx {
772745

773746
throw new ResolutionError(err, [item]);
774747
} finally {
775-
this._itemStateStack.popItem();
748+
this._itemStateStack.pop('item');
776749
}
777750
}
778751

packages/typegpu/src/types.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,29 @@ export type FunctionScopeLayer = {
109109
reportedReturnTypes: Set<AnyData>;
110110
};
111111

112+
export type SlotBindingLayer = {
113+
type: 'slotBinding';
114+
bindingMap: WeakMap<TgpuSlot<unknown>, unknown>;
115+
};
116+
117+
export type BlockScopeLayer = {
118+
type: 'blockScope';
119+
declarations: Map<string, Snippet>;
120+
};
121+
122+
export type StackLayer =
123+
| ItemLayer
124+
| SlotBindingLayer
125+
| FunctionScopeLayer
126+
| BlockScopeLayer;
127+
112128
export interface ItemStateStack {
113129
readonly itemDepth: number;
114130
readonly topItem: ItemLayer;
115131
readonly topFunctionScope: FunctionScopeLayer | undefined;
116132

117133
pushItem(): void;
118-
popItem(): void;
119134
pushSlotBindings(pairs: SlotValuePair<unknown>[]): void;
120-
popSlotBindings(): void;
121135
pushFunctionScope(
122136
functionType: 'normal' | TgpuShaderStage,
123137
args: Snippet[],
@@ -129,10 +143,11 @@ export interface ItemStateStack {
129143
returnType: AnyData | undefined,
130144
externalMap: Record<string, unknown>,
131145
): FunctionScopeLayer;
132-
popFunctionScope(): void;
133146
pushBlockScope(): void;
134-
popBlockScope(): void;
135-
pop(type?: 'functionScope' | 'blockScope' | 'slotBinding' | 'item'): void;
147+
148+
pop<T extends StackLayer['type']>(type: T): Extract<StackLayer, { type: T }>;
149+
pop(): StackLayer | undefined;
150+
136151
readSlot<T>(slot: TgpuSlot<T>): T | undefined;
137152
getSnippetById(id: string): Snippet | undefined;
138153
defineBlockVariable(id: string, snippet: Snippet): void;

packages/typegpu/tests/slot.test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, expect } from 'vitest';
22
import * as d from '../src/data/index.ts';
3-
import * as std from '../src/std/index.ts';
43
import tgpu from '../src/index.ts';
4+
import * as std from '../src/std/index.ts';
55
import { it } from './utils/extendedIt.ts';
66

77
const RED = 'vec3f(1., 0., 0.)';
@@ -363,4 +363,32 @@ describe('tgpu.slot', () => {
363363
}"
364364
`);
365365
});
366+
367+
it('includes slot bindings in toString', () => {
368+
const firstSlot = tgpu.slot<number>();
369+
const secondSlot = tgpu.slot<number>();
370+
const thirdSlot = tgpu.slot<number>();
371+
372+
const getSize = tgpu.fn([], d.f32)(() =>
373+
firstSlot.$ + secondSlot.$ + thirdSlot.$
374+
)
375+
.with(firstSlot, 1)
376+
.with(secondSlot, 2)
377+
.with(thirdSlot, 3);
378+
379+
expect(getSize.toString()).toMatchInlineSnapshot(
380+
`"fn:getSize[firstSlot=1, secondSlot=2, thirdSlot=3]"`,
381+
);
382+
});
383+
384+
it('safe stringifies in toString', () => {
385+
const slot = tgpu.slot<d.v4f>();
386+
387+
const getSize = tgpu.fn([], d.f32)(() => slot.$.x)
388+
.with(slot, d.vec4f(1, 2, 3, 4));
389+
390+
expect(getSize.toString()).toMatchInlineSnapshot(
391+
`"fn:getSize[slot=vec4f(1, 2, 3, 4)]"`,
392+
);
393+
});
366394
});

packages/typegpu/tests/tgsl/wgslGenerator.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ describe('wgslGenerator', () => {
338338
const res2 = wgslGenerator.expression(
339339
(astInfo.ast?.body[1][1] as tinyest.Const)[2],
340340
);
341-
ctx[$internal].itemStateStack.popBlockScope();
341+
ctx[$internal].itemStateStack.pop('blockScope');
342342

343343
expect(res2.dataType).toStrictEqual(d.vec4f);
344344

@@ -353,7 +353,7 @@ describe('wgslGenerator', () => {
353353
const res4 = wgslGenerator.expression(
354354
astInfo.ast?.body[1][2] as tinyest.Expression,
355355
);
356-
ctx[$internal].itemStateStack.popBlockScope();
356+
ctx[$internal].itemStateStack.pop('blockScope');
357357

358358
expect(res3.dataType).toStrictEqual(d.atomic(d.u32));
359359
expect(res4.dataType).toStrictEqual(Void);

packages/typegpu/tests/utils/parseResolved.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ function extractSnippetFromFn(cb: () => unknown): Snippet {
5858
} finally {
5959
if (pushedFnScope) {
6060
ctx.popBlockScope();
61-
ctx[$internal].itemStateStack.popFunctionScope();
62-
ctx[$internal].itemStateStack.popItem();
61+
ctx[$internal].itemStateStack.pop('functionScope');
62+
ctx[$internal].itemStateStack.pop('item');
6363
}
6464
ctx.popMode('codegen');
6565
}

0 commit comments

Comments
 (0)