fix: Forbid multiple $uses calls#2621
Conversation
|
pkg.pr.new packages benchmark commit |
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 0 | 297 | 23 | 0 |
import * as ... in PR vs import * as ... in target (did bundle size increase?):
| Test | tsdown |
|---|---|
| common_fullScreenTriangle.ts | 40.36 kB ( |
| STATIC_common.ts | 57.28 kB ( |
import { ... } in PR vs import * as ... in PR (is the library tree-Shakeable?):
Click to reveal the results table (297 entries).
| Test | tsdown |
|---|---|
| d_Void.ts | 87.36 kB ( |
| d_sampler.ts | 87.36 kB ( |
| d_isPtr.ts | 87.36 kB ( |
| d_comparisonSampler.ts | 87.37 kB ( |
| d_isSizeAttrib.ts | 87.37 kB ( |
| d_isWgslArray.ts | 87.37 kB ( |
| d_isAlignAttrib.ts | 87.37 kB ( |
| d_isWgslStruct.ts | 87.37 kB ( |
| d_isAtomic.ts | 87.36 kB ( |
| d_isBuiltinAttrib.ts | 87.37 kB ( |
| d_isLocationAttrib.ts | 87.37 kB ( |
| d_isDecorated.ts | 87.37 kB ( |
| d_isInterpolateAttrib.ts | 87.38 kB ( |
| d_atomic.ts | 87.36 kB ( |
| d_ptrHandle.ts | 87.37 kB ( |
| d_ptrUniform.ts | 87.37 kB ( |
| d_ptrStorage.ts | 87.37 kB ( |
| d_ptrPrivate.ts | 87.37 kB ( |
| d_ptrFn.ts | 87.36 kB ( |
| d_ptrWorkgroup.ts | 87.37 kB ( |
| d_textureExternal.ts | 87.37 kB ( |
| d_textureStorage1d.ts | 87.37 kB ( |
| d_textureStorage2d.ts | 87.37 kB ( |
| d_textureStorage3d.ts | 87.37 kB ( |
| d_textureStorage2dArray.ts | 87.38 kB ( |
| d_isDisarray.ts | 87.37 kB ( |
| d_isUnstruct.ts | 87.37 kB ( |
| d_isLooseDecorated.ts | 87.37 kB ( |
| d_isLooseData.ts | 87.37 kB ( |
| d_isWgslData.ts | 87.37 kB ( |
| d_unstruct.ts | 87.36 kB ( |
| d_isData.ts | 87.36 kB ( |
| d_deepEqual.ts | 87.37 kB ( |
| d_struct.ts | 87.36 kB ( |
| d_ref.ts | 87.36 kB ( |
| std_discard.ts | 103.09 kB ( |
| std_copy.ts | 103.09 kB ( |
| std_arrayLength.ts | 103.10 kB ( |
| std_isBeingTranspiled.ts | 103.10 kB ( |
| std_getTargetShaderLanguage.ts | 103.11 kB ( |
| std_extensionEnabled.ts | 103.10 kB ( |
| std_range.ts | 103.09 kB ( |
| std_dpdx.ts | 103.09 kB ( |
| std_fwidthCoarse.ts | 103.10 kB ( |
| std_dpdxCoarse.ts | 103.10 kB ( |
| std_dpdyCoarse.ts | 103.10 kB ( |
| std_fwidthFine.ts | 103.10 kB ( |
| std_dpdxFine.ts | 103.09 kB ( |
| std_dpdyFine.ts | 103.09 kB ( |
| std_fwidth.ts | 103.09 kB ( |
| std_dpdy.ts | 103.09 kB ( |
| d_bool.ts | 87.36 kB ( |
| d_f16.ts | 87.36 kB ( |
| d_f32.ts | 87.36 kB ( |
| d_i32.ts | 87.36 kB ( |
| d_u32.ts | 87.36 kB ( |
| d_u16.ts | 87.36 kB ( |
| std_atomicLoad.ts | 103.10 kB ( |
| std_textureBarrier.ts | 103.10 kB ( |
| std_atomicStore.ts | 103.10 kB ( |
| std_workgroupBarrier.ts | 103.10 kB ( |
| std_storageBarrier.ts | 103.10 kB ( |
| std_atomicAdd.ts | 103.09 kB ( |
| std_atomicAnd.ts | 103.09 kB ( |
| std_atomicMax.ts | 103.09 kB ( |
| std_atomicMin.ts | 103.09 kB ( |
| std_atomicSub.ts | 103.09 kB ( |
| std_atomicXor.ts | 103.09 kB ( |
| std_atomicOr.ts | 103.09 kB ( |
| d_textureDepth2d.ts | 87.37 kB ( |
| d_textureDepthCube.ts | 87.37 kB ( |
| d_texture1d.ts | 87.37 kB ( |
| d_texture2d.ts | 87.37 kB ( |
| d_texture3d.ts | 87.37 kB ( |
| d_textureDepth2dArray.ts | 87.38 kB ( |
| d_textureCube.ts | 87.37 kB ( |
| d_textureDepthCubeArray.ts | 87.38 kB ( |
| d_textureDepthMultisampled2d.ts | 87.38 kB ( |
| d_texture2dArray.ts | 87.37 kB ( |
| d_textureCubeArray.ts | 87.37 kB ( |
| d_textureMultisampled2d.ts | 87.38 kB ( |
| d_disarrayOf.ts | 87.37 kB ( |
| d_vec2b.ts | 87.36 kB ( |
| d_vec2f.ts | 87.36 kB ( |
| d_vec2h.ts | 87.36 kB ( |
| d_vec2i.ts | 87.36 kB ( |
| d_vec2u.ts | 87.36 kB ( |
| d_vec3b.ts | 87.36 kB ( |
| d_vec3f.ts | 87.36 kB ( |
| d_vec3h.ts | 87.36 kB ( |
| d_vec3i.ts | 87.36 kB ( |
| d_vec3u.ts | 87.36 kB ( |
| d_vec4b.ts | 87.36 kB ( |
| d_vec4f.ts | 87.36 kB ( |
| d_vec4h.ts | 87.36 kB ( |
| d_vec4i.ts | 87.36 kB ( |
| d_vec4u.ts | 87.36 kB ( |
| std_subgroupAdd.ts | 103.10 kB ( |
| std_subgroupBroadcastFirst.ts | 103.11 kB ( |
| std_subgroupExclusiveAdd.ts | 103.11 kB ( |
| std_subgroupExclusiveMul.ts | 103.11 kB ( |
| std_subgroupInclusiveAdd.ts | 103.11 kB ( |
| std_subgroupInclusiveMul.ts | 103.11 kB ( |
| std_subgroupShuffleDown.ts | 103.10 kB ( |
| std_subgroupShuffleXor.ts | 103.10 kB ( |
| std_subgroupBroadcast.ts | 103.10 kB ( |
| std_subgroupShuffleUp.ts | 103.10 kB ( |
| std_subgroupShuffle.ts | 103.10 kB ( |
| std_subgroupBallot.ts | 103.10 kB ( |
| std_subgroupElect.ts | 103.10 kB ( |
| std_subgroupAll.ts | 103.10 kB ( |
| std_subgroupAnd.ts | 103.10 kB ( |
| std_subgroupAny.ts | 103.10 kB ( |
| std_subgroupMax.ts | 103.10 kB ( |
| std_subgroupMin.ts | 103.10 kB ( |
| std_subgroupMul.ts | 103.10 kB ( |
| std_subgroupXor.ts | 103.10 kB ( |
| std_subgroupOr.ts | 103.10 kB ( |
| d_formatToWGSLType.ts | 87.37 kB ( |
| d_uint8.ts | 87.36 kB ( |
| d_unorm10_10_10_2.ts | 87.37 kB ( |
| d_unorm8x4_bgra.ts | 87.37 kB ( |
| d_float16x2.ts | 87.37 kB ( |
| d_float16x4.ts | 87.37 kB ( |
| d_float32x2.ts | 87.37 kB ( |
| d_float32x3.ts | 87.37 kB ( |
| d_float32x4.ts | 87.37 kB ( |
| d_snorm16x2.ts | 87.37 kB ( |
| d_snorm16x4.ts | 87.37 kB ( |
| d_unorm16x2.ts | 87.37 kB ( |
| d_unorm16x4.ts | 87.37 kB ( |
| d_sint16x2.ts | 87.36 kB ( |
| d_sint16x4.ts | 87.36 kB ( |
| d_sint32x2.ts | 87.36 kB ( |
| d_sint32x3.ts | 87.36 kB ( |
| d_sint32x4.ts | 87.36 kB ( |
| d_snorm8x2.ts | 87.36 kB ( |
| d_snorm8x4.ts | 87.36 kB ( |
| d_uint16x2.ts | 87.36 kB ( |
| d_uint16x4.ts | 87.36 kB ( |
| d_uint32x2.ts | 87.36 kB ( |
| d_uint32x3.ts | 87.36 kB ( |
| d_uint32x4.ts | 87.36 kB ( |
| d_unorm8x2.ts | 87.36 kB ( |
| d_unorm8x4.ts | 87.36 kB ( |
| d_float16.ts | 87.36 kB ( |
| d_float32.ts | 87.36 kB ( |
| d_sint8x2.ts | 87.36 kB ( |
| d_sint8x4.ts | 87.36 kB ( |
| d_snorm16.ts | 87.36 kB ( |
| d_uint8x2.ts | 87.36 kB ( |
| d_uint8x4.ts | 87.36 kB ( |
| d_unorm16.ts | 87.36 kB ( |
| d_sint16.ts | 87.36 kB ( |
| d_sint32.ts | 87.36 kB ( |
| d_snorm8.ts | 87.36 kB ( |
| d_uint16.ts | 87.36 kB ( |
| d_uint32.ts | 87.36 kB ( |
| d_unorm8.ts | 87.36 kB ( |
| d_sint8.ts | 87.36 kB ( |
| d_packedFormats.ts | 87.37 kB ( |
| d_isPackedData.ts | 87.37 kB ( |
| std_textureDimensions.ts | 103.10 kB ( |
| std_textureGather.ts | 103.10 kB ( |
| std_textureSampleBaseClampToEdge.ts | 103.11 kB ( |
| std_textureSampleCompareLevel.ts | 103.11 kB ( |
| std_textureSampleCompare.ts | 103.11 kB ( |
| std_textureSampleLevel.ts | 103.10 kB ( |
| std_textureSampleBias.ts | 103.10 kB ( |
| std_textureSampleGrad.ts | 103.10 kB ( |
| std_textureSample.ts | 103.10 kB ( |
| std_textureStore.ts | 103.10 kB ( |
| std_textureLoad.ts | 103.10 kB ( |
| d_alignmentOf.ts | 87.37 kB ( |
| std_translation4.ts | 103.10 kB ( |
| std_rotationX4.ts | 103.10 kB ( |
| std_rotationY4.ts | 103.10 kB ( |
| std_rotationZ4.ts | 103.10 kB ( |
| std_identity2.ts | 103.09 kB ( |
| std_identity3.ts | 103.09 kB ( |
| std_identity4.ts | 103.09 kB ( |
| std_scaling4.ts | 103.09 kB ( |
| d_isBuiltin.ts | 87.37 kB ( |
| d_sizeOf.ts | 87.36 kB ( |
| d_isContiguous.ts | 87.37 kB ( |
| d_getLongestContiguousPrefix.ts | 87.38 kB ( |
| d_arrayOf.ts | 87.36 kB ( |
| d_size.ts | 87.36 kB ( |
| d_align.ts | 87.36 kB ( |
| d_location.ts | 87.36 kB ( |
| d_interpolate.ts | 87.37 kB ( |
| d_invariant.ts | 87.37 kB ( |
| d_mat4x4f.ts | 87.36 kB ( |
| d_mat2x2f.ts | 87.36 kB ( |
| d_mat3x3f.ts | 87.36 kB ( |
| d_matToArray.ts | 87.37 kB ( |
| d_builtin.ts | 87.36 kB ( |
| std_unpack2x16float.ts | 103.10 kB ( |
| std_unpack4x8unorm.ts | 103.10 kB ( |
| std_pack2x16float.ts | 103.10 kB ( |
| std_pack4x8unorm.ts | 103.10 kB ( |
| std_bitcastU32toF32.ts | 103.10 kB ( |
| std_bitcastU32toI32.ts | 103.10 kB ( |
| std_neg.ts | 103.09 kB ( |
| std_bitShiftRight.ts | 103.10 kB ( |
| std_bitShiftLeft.ts | 103.10 kB ( |
| std_add.ts | 103.09 kB ( |
| std_div.ts | 103.09 kB ( |
| std_mod.ts | 103.09 kB ( |
| std_mul.ts | 103.09 kB ( |
| std_sub.ts | 103.09 kB ( |
| std_translate4.ts | 103.10 kB ( |
| std_rotateX4.ts | 103.09 kB ( |
| std_scale4.ts | 103.09 kB ( |
| std_rotateY4.ts | 103.09 kB ( |
| std_rotateZ4.ts | 103.09 kB ( |
| d_memoryLayoutOf.ts | 87.37 kB ( |
| std_and.ts | 103.09 kB ( |
| std_or.ts | 103.09 kB ( |
| std_select.ts | 103.09 kB ( |
| std_allEq.ts | 103.09 kB ( |
| std_all.ts | 103.09 kB ( |
| std_not.ts | 103.09 kB ( |
| std_eq.ts | 103.09 kB ( |
| std_lt.ts | 103.09 kB ( |
| std_ne.ts | 103.09 kB ( |
| std_isCloseTo.ts | 103.09 kB ( |
| std_any.ts | 103.09 kB ( |
| std_ge.ts | 103.09 kB ( |
| std_gt.ts | 103.09 kB ( |
| std_le.ts | 103.09 kB ( |
| std_dot4U8Packed.ts | 103.10 kB ( |
| std_length.ts | 103.09 kB ( |
| std_countTrailingZeros.ts | 103.10 kB ( |
| std_distance.ts | 103.09 kB ( |
| std_dot.ts | 103.09 kB ( |
| std_countLeadingZeros.ts | 103.10 kB ( |
| std_firstTrailingBit.ts | 103.10 kB ( |
| std_firstLeadingBit.ts | 103.10 kB ( |
| std_fract.ts | 103.09 kB ( |
| std_frexp.ts | 103.09 kB ( |
| std_modf.ts | 103.09 kB ( |
| std_quantizeToF16.ts | 103.10 kB ( |
| std_mix.ts | 103.09 kB ( |
| std_countOneBits.ts | 103.10 kB ( |
| std_dot4I8Packed.ts | 103.10 kB ( |
| std_determinant.ts | 103.10 kB ( |
| std_extractBits.ts | 103.10 kB ( |
| std_faceForward.ts | 103.10 kB ( |
| std_inverseSqrt.ts | 103.10 kB ( |
| std_reverseBits.ts | 103.10 kB ( |
| std_insertBits.ts | 103.10 kB ( |
| std_smoothstep.ts | 103.10 kB ( |
| std_normalize.ts | 103.09 kB ( |
| std_transpose.ts | 103.09 kB ( |
| std_saturate.ts | 103.09 kB ( |
| std_degrees.ts | 103.09 kB ( |
| std_radians.ts | 103.09 kB ( |
| std_reflect.ts | 103.09 kB ( |
| std_refract.ts | 103.09 kB ( |
| std_acosh.ts | 103.09 kB ( |
| std_asinh.ts | 103.09 kB ( |
| std_atan2.ts | 103.09 kB ( |
| std_atanh.ts | 103.09 kB ( |
| std_clamp.ts | 103.09 kB ( |
| std_cross.ts | 103.09 kB ( |
| std_floor.ts | 103.09 kB ( |
| std_ldexp.ts | 103.09 kB ( |
| std_round.ts | 103.09 kB ( |
| std_trunc.ts | 103.09 kB ( |
| std_acos.ts | 103.09 kB ( |
| std_asin.ts | 103.09 kB ( |
| std_atan.ts | 103.09 kB ( |
| std_ceil.ts | 103.09 kB ( |
| std_cosh.ts | 103.09 kB ( |
| std_exp2.ts | 103.09 kB ( |
| std_log2.ts | 103.09 kB ( |
| std_sign.ts | 103.09 kB ( |
| std_sinh.ts | 103.09 kB ( |
| std_sqrt.ts | 103.09 kB ( |
| std_step.ts | 103.09 kB ( |
| std_tanh.ts | 103.09 kB ( |
| std_abs.ts | 103.09 kB ( |
| std_cos.ts | 103.09 kB ( |
| std_exp.ts | 103.09 kB ( |
| std_fma.ts | 103.09 kB ( |
| std_log.ts | 103.09 kB ( |
| std_max.ts | 103.09 kB ( |
| std_min.ts | 103.09 kB ( |
| std_pow.ts | 103.09 kB ( |
| std_sin.ts | 103.09 kB ( |
| std_tan.ts | 103.09 kB ( |
| common_fullScreenTriangle.ts | 57.13 kB ( |
| common_writeSoA.ts | 57.12 kB ( |
| STATIC_allImports.ts | 287.08 kB ( |
| STATIC_d.ts | 87.36 kB ( |
| STATIC_std.ts | 103.08 kB ( |
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [1.02, 2.00, 4.19, 6.84, 8.21, 11.41, 23.52, 23.33]
line [1.04, 2.12, 4.50, 6.91, 7.82, 12.05, 23.99, 26.36]
line [1.00, 1.88, 3.94, 6.18, 7.65, 12.08, 22.42, 23.66]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.33, 0.56, 0.76, 0.86, 1.14, 1.22, 1.48, 1.70]
line [0.38, 0.62, 0.78, 0.90, 1.23, 1.30, 1.54, 1.74]
line [0.32, 0.69, 0.70, 0.85, 1.19, 1.24, 1.47, 1.67]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [1.01, 2.09, 4.11, 7.18, 13.07, 27.65, 57.34, 115.25]
line [0.93, 2.16, 3.47, 6.73, 13.06, 27.64, 56.47, 117.32]
line [0.84, 2.13, 3.76, 6.31, 12.92, 25.22, 55.20, 114.71]
|
78ed65c to
7c7faad
Compare
|
@pullfrog review, be thorough |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — replaces the recursive mergeExternals / array-based deferred externals model with a structured FnExternals type and mergeFunctionExternals, forbidding multiple $uses() calls and detecting name collisions between user-provided externals and arg/return types.
- Structured
FnExternalstype — replacesExternalMap[]with a typed object carryinguserProvided,pluginProvided,args, andoutslots, making the source of each external explicit. mergeFunctionExternals— replaces the old recursivemergeExternalswith a flat merge that pickspluginProvidedoveruserProvidedas a base, then layersargs/outon top, throwing on unequal key collisions.- Forbid multiple
$uses()—tgpuDeclare.impl,TgpuRawCodeSnippetImpl, andFnCore.setExternals('userProvided', ...)all throw if$useshas already been called. - Forbid
$useson plugin-processed functions —setExternals('userProvided', ...)throws ifpluginProvidedhas already been set. - Entry function
Out/inexternals — gated behindtypeof implementation === 'string'in fragment/vertex fn, since thefnCore.resolveTGSL path setsoutvia the AST's second parameter. - Tests — removed obsolete multi-
$uses/ merge mutation tests fromfunction.test.ts; added name-collision detection tests andmultiple $uses throwstests indeclare.test.ts,rawCodeSnippet.test.ts, andexternals.test.ts.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Reviewed changes — replaces the multi-call $uses pattern with a single-call constraint and categorized externals system, enabling collision detection between user-provided, plugin-provided, args, and return-type externals.
- Add
FnExternalstype with categorized slots — separatesuserProvided,pluginProvided,args, andoutinto distinct categories infnCore.ts, replacing the flat array ofExternalMap. - Replace
mergeExternalswithmergeFunctionExternals— merges the four externals categories at resolve time with collision detection for name conflicts with args/return types. - Forbid multiple
$usesondeclare,rawCodeSnippet, and functions — throws a descriptive error directing users to slots or accessors for overriding. - Guard
setExternals('out', ...)on string implementations — intgpuFragmentFnandtgpuVertexFn, only setsoutexternals for string (raw WGSL) implementations since TGSL implementations handle it insidefnCore.resolve(). - Add collision detection tests — covers
Out/inconflicts in raw WGSL entrypoints, argument collisions, return-type collisions, and redundant (same-value) externals.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
| externalsToApply.push(newExternals); | ||
|
|
||
| setExternals(key: keyof FnExternals, newExternal: ExternalMap): void { | ||
| if (key === 'userProvided') { |
There was a problem hiding this comment.
ℹ️ The pluginProvided guard only fires when pluginProvided has already been set before userProvided. In normal flow, pluginProvided is set during core.resolve() — after any $uses call. This means calling $uses() on a TGSL function (whose implementation already has plugin metadata) will silently accept externals that are then ignored by mergeFunctionExternals (which picks pluginProvided over userProvided). The explicit error message on line 86 is unreachable in practice.
Technical details
# Unreachable `pluginProvided` guard in `setExternals`
## Affected sites
- `packages/typegpu/src/core/function/fnCore.ts:84-88` — `if ('pluginProvided' in externals)` check
- `packages/typegpu/src/core/resolve/externals.ts:21` — `mergeFunctionExternals` picks `pluginProvided ?? userProvided`
## Required outcome
- Either detect the conflict in both directions (when `pluginProvided` is set and `userProvided` already exists, or vice versa)
- Or throw before `$uses` completes on TGSL functions (by checking for plugin metadata eagerly, before resolution)
## Suggested approach
In `setExternals`, also guard the `pluginProvided` path:
```ts
if (key === 'pluginProvided' && 'userProvided' in externals) {
throw new Error("...cannot call '$uses' on functions whose metadata was provided by unplugin-typegpu.");
}
```
Or, move the plugin-detection check to the `$uses` call site so it throws eagerly: check `getFunctionMetadata(implementation)` at the time `$uses` is called (requires passing the implementation reference to the `$uses` wrapper).
No description provided.