You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since #730, @JS types defined in one module can be referenced from @JS APIs in other modules within the same package. However, type identity in the skeleton and in the generated glue is the unqualified type name — abiName carries the namespace but not the module. When two linked modules define @JS types with the same name (e.g. @JS struct Point in both ModuleA and ModuleB), several generated-name surfaces collide:
Stack ABI intrinsics (silent data corruption): Both modules' generated Swift declares
WebAssembly imports with the same module + name unify, and the linker assigns bjs["swift_js_struct_lower_Point"] twice — last one wins. Both modules end up calling the same handler, so one module's structs are encoded/decoded with the other's field layout. No diagnostic at build time or runtime.
JS helper tables:structHelpers / enum helper factories are keyed by unqualified name inside createInstantiator — same last-wins behavior.
Exposed thunks:@_expose(wasm, "bjs_Point_init") (and method/deinit thunks) are emitted by both modules, producing duplicate export names.
TypeScript declarations: two interface Point declarations in one bridge-js.d.ts — TypeScript declaration-merges them, which is silent when the field sets are compatible and produces confusing errors when they are not.
Reference resolution: independent of naming, a skeleton reference like .swiftStruct("Point") is unqualified, so the linker resolves it by name-matching across all skeletons — with two candidates the choice is arbitrary. Renaming the ABI surfaces alone is not sufficient; the reference side needs the defining module too.
Module-qualify the internal ABI names (swift_js_struct_lower_<Module>_<Name>, bjs_<Module>_…). Newer name families already follow this pattern — closure invokes (invoke_js_callback_<module>_<mangleName>) and promise settlement helpers (promise_resolve_<module>_<mangled>) — it is only the older core names that predate it.
Keep the public JS surface flat (exports.Point, TS declarations) and emit a build-time linker diagnostic when two modules expose the same public name, mirroring how BridgeJS: Use @JS types from other modules in the same package #730 handles Swift-side ambiguity with a diagnostic that asks for explicit qualification.
Overview
Since #730,
@JStypes defined in one module can be referenced from@JSAPIs in other modules within the same package. However, type identity in the skeleton and in the generated glue is the unqualified type name —abiNamecarries the namespace but not the module. When two linked modules define@JStypes with the same name (e.g.@JS struct Pointin bothModuleAandModuleB), several generated-name surfaces collide:Stack ABI intrinsics (silent data corruption): Both modules' generated Swift declares
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Point")WebAssembly imports with the same module + name unify, and the linker assigns
bjs["swift_js_struct_lower_Point"]twice — last one wins. Both modules end up calling the same handler, so one module's structs are encoded/decoded with the other's field layout. No diagnostic at build time or runtime.JS helper tables:
structHelpers/ enum helper factories are keyed by unqualified name insidecreateInstantiator— same last-wins behavior.Exposed thunks:
@_expose(wasm, "bjs_Point_init")(and method/deinit thunks) are emitted by both modules, producing duplicate export names.TypeScript declarations: two
interface Pointdeclarations in onebridge-js.d.ts— TypeScript declaration-merges them, which is silent when the field sets are compatible and produces confusing errors when they are not.Reference resolution: independent of naming, a skeleton reference like
.swiftStruct("Point")is unqualified, so the linker resolves it by name-matching across all skeletons — with two candidates the choice is arbitrary. Renaming the ABI surfaces alone is not sufficient; the reference side needs the defining module too.Possible direction
@JStypes from other modules in the same package #730 already established that the skeleton format does not need to stay backward compatible.swift_js_struct_lower_<Module>_<Name>,bjs_<Module>_…). Newer name families already follow this pattern — closure invokes (invoke_js_callback_<module>_<mangleName>) and promise settlement helpers (promise_resolve_<module>_<mangled>) — it is only the older core names that predate it.exports.Point, TS declarations) and emit a build-time linker diagnostic when two modules expose the same public name, mirroring how BridgeJS: Use@JStypes from other modules in the same package #730 handles Swift-side ambiguity with a diagnostic that asks for explicit qualification.