@@ -420,22 +420,13 @@ public struct BridgeJSLink {
420420 )
421421 }
422422
423- /// Emits a `{ lower, lift }` codec literal for one bridgeable type.
424- /// `prefix` is prepended to the opening brace (e.g. an assignment) and
425- /// `suffix` is appended to the closing brace (e.g. `","` in an array).
426- private func appendGenericCodecLiteral(
427- type: BridgeType ,
428- into printer: CodeFragmentPrinter ,
429- prefix: String = " " ,
430- suffix: String = " , "
431- ) throws {
432- try ContainerCodecJS . writeCodecLiteral (
433- type: type,
434- into: printer,
435- context: makeCodecPrintContext ( printer: printer) ,
436- prefix: prefix,
437- suffix: suffix
438- )
423+ /// Returns the module-scope codec helper for one bridgeable type, declaring
424+ /// it if this is the first reference.
425+ ///
426+ /// The registration table and the container combinators' element positions
427+ /// go through the same helper, so a type's stack ABI is described once.
428+ private func genericCodecReference( type: BridgeType , into printer: CodeFragmentPrinter ) throws -> String {
429+ try ContainerCodecJS . codecExpression ( for: type, context: makeCodecPrintContext ( printer: printer) )
439430 }
440431
441432 /// Writes the body shared by every registration hook: verify the codec array
@@ -509,10 +500,13 @@ public struct BridgeJSLink {
509500 printer. write ( " bjs[ \" \( hookName) \" ] = function(base, count) { " )
510501 try printer. indent {
511502 // Same order as the module's Swift registration function.
503+ let codecNames = try moduleEntries. map {
504+ try genericCodecReference ( type: $0. bridgeType, into: printer)
505+ }
512506 printer. write ( " const codecs = [ " )
513- try printer. indent {
514- for entry in moduleEntries {
515- try appendGenericCodecLiteral ( type : entry . bridgeType , into : printer )
507+ printer. indent {
508+ for name in codecNames {
509+ printer . write ( " \( name ) , " )
516510 }
517511 }
518512 printer. write ( " ]; " )
@@ -1303,6 +1297,18 @@ public struct BridgeJSLink {
13031297 printer. nextLine ( )
13041298 }
13051299
1300+ // The named codec helpers come after the intrinsics because they are
1301+ // built out of the combinators and the primitive codec table, and
1302+ // before everything that uses them: they are hoisted here so that no
1303+ // call site ever composes a codec. Helpers that delegate to the
1304+ // `structHelpers` / `enumHelpers` tables only read those tables when
1305+ // called, so declaring them ahead of the tables being populated is
1306+ // fine.
1307+ if intrinsicRegistry. hasNamedCodecs {
1308+ printer. write ( lines: intrinsicRegistry. emitNamedCodecLines ( ) )
1309+ printer. nextLine ( )
1310+ }
1311+
13061312 printer. write ( lines: bodyPrinter. lines)
13071313 }
13081314 printer. indent ( )
@@ -1406,12 +1412,54 @@ public struct BridgeJSLink {
14061412 }
14071413 }
14081414 }
1415+ intrinsicRegistry. typeOwnerModules = collectTypeOwnerModules ( )
14091416 let data = try collectLinkData ( )
14101417 let outputJs = try generateJavaScript ( data: data)
14111418 let outputDts = generateTypeScript ( data: data)
14121419 return ( outputJs, outputDts)
14131420 }
14141421
1422+ /// Maps every type name a `BridgeType` can carry to the module that declares
1423+ /// it, so identifiers minted from type names can be module-qualified.
1424+ ///
1425+ /// A name declared by two modules is a pre-existing ambiguity in the
1426+ /// skeleton format (`BridgeType` carries only the name), so the first
1427+ /// declaration wins, which keeps the output deterministic.
1428+ private func collectTypeOwnerModules( ) -> [ String : String ] {
1429+ var result : [ String : String ] = [ : ]
1430+ func record( _ name: String , _ moduleName: String ) {
1431+ if result [ name] == nil {
1432+ result [ name] = moduleName
1433+ }
1434+ }
1435+ for unified in skeletons {
1436+ let moduleName = unified. moduleName
1437+ if let skeleton = unified. exported {
1438+ for structDef in skeleton. structs {
1439+ record ( structDef. name, moduleName)
1440+ record ( structDef. abiName, moduleName)
1441+ }
1442+ for klass in skeleton. classes {
1443+ record ( klass. name, moduleName)
1444+ record ( klass. abiName, moduleName)
1445+ }
1446+ for enumDef in skeleton. enums {
1447+ record ( enumDef. name, moduleName)
1448+ record ( enumDef. abiName, moduleName)
1449+ }
1450+ for protocolDef in skeleton. protocols {
1451+ record ( protocolDef. name, moduleName)
1452+ }
1453+ }
1454+ for file in unified. imported? . children ?? [ ] {
1455+ for type in file. types {
1456+ record ( type. name, moduleName)
1457+ }
1458+ }
1459+ }
1460+ return result
1461+ }
1462+
14151463 private func enumHelperAssignments( ) -> CodeFragmentPrinter {
14161464 let printer = CodeFragmentPrinter ( )
14171465
0 commit comments