BridgeJS: Same-named `@JS` types across modules collide silently in generated glue
@krodak ci sta già lavorando.
Dal 6/7/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
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.
- Lingua principale
- Swift
- Stelle
- 986
- Fork
- 76
- Merge medio
- 21h 11m
- PR unite (30g)
- 4
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di swiftwasm/JavaScriptKit
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 55/100
swiftwasm/JavaScriptKit#793 ·
-
[SwiftBuild] Preserve duplicate archive members when SwiftBuild expands static archives for linking Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
swiftwasm/JavaScriptKit#781 · 3 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
swiftwasm/JavaScriptKit#773 ·
-
swiftwasm/JavaScriptKit#767 · 1 assegnatario ·
-
swiftwasm/JavaScriptKit#761 · 1 assegnatario ·
Tutte le issue di swiftwasm/JavaScriptKit
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
manaflow-ai/cmux#13763 ·
-
type: feature request
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
googleapis/google-cloud-swift#1036 · 1 commento ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 78/100
wultra/mtoken-sdk-ios#253 ·
-
The correction-threshold rationale says 17 restraint cases collide; the current corpus has 16 Apertaarea:dictation documentation P2
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
uttrflow/uttrflow-swift#1180 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100