swiftwasm / swiftwasm/JavaScriptKit
BridgeJS: Same-named `@JS` types across modules collide silently in generated glue
@krodak 已经在做这个了。
开始于 2026年7月6日。
- 主要语言
- Swift
- 星标
- 986
- 派生
- 76
- 平均合并
- 21 小时 11 分钟
- 30 天内合并 PR
- 4
描述
Overview
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
@_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 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.
Public JS declarations (fails loudly, related): even when the colliding types live under different @JS(namespace:) paths — where no public-surface conflict exists — the generated JS still declares classes and enum value objects with flat top-level identifiers (class Point { … }, const PointValues = …) before wiring them into their namespace objects, and bridge-js.d.ts emits the corresponding declarations unscoped. Two same-named types in different namespaces therefore produce duplicate declarations in one scope: a load-time SyntaxError on the JS side and duplicate-identifier errors in the .d.ts. Unlike the ABI surfaces above this fails loudly rather than corrupting data, but it makes same-named types unusable across modules even when their public paths don't overlap.
Possible direction
- Make type identity in the skeleton module-aware (defining module + name). #730 already established that the skeleton format does not need to stay backward compatible.
- 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 access paths flat (
exports.Point, namespace objects, TS types) and emit a build-time linker diagnostic when two modules expose the identical public name at the same namespace path, mirroring how #730 handles Swift-side ambiguity with a diagnostic that asks for explicit qualification. - For the declaration surface: declare classes and enum value objects under unique internal identifiers (the module-qualified ABI name is a natural choice), bind public names only through namespace objects /
exports, and scope.d.tsdeclarations for namespaced types insidedeclare namespaceblocks. Public access paths stay exactly as today; only the internal declaration identifiers change, so same-named types in different namespaces become fully usable.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
评估
这个 Issue 还没有评估数据。