Skip to content

Commit e7b8427

Browse files
committed
BridgeJS: Fix protocol existential lowering in Swift-to-JS direction
1 parent 7dd0263 commit e7b8427

34 files changed

+740
-108
lines changed

Benchmarks/Sources/Generated/BridgeJS.swift

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -491,10 +491,13 @@ public func _bjs_EnumRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi
491491
#endif
492492
}
493493

494-
extension EnumRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
494+
extension EnumRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
495495
var jsValue: JSValue {
496496
return .object(JSObject(id: UInt32(bitPattern: _bjs_EnumRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
497497
}
498+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
499+
_bjs_EnumRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
500+
}
498501
}
499502

500503
#if arch(wasm32)
@@ -628,10 +631,13 @@ public func _bjs_ComplexResultRoundtrip_deinit(_ pointer: UnsafeMutableRawPointe
628631
#endif
629632
}
630633

631-
extension ComplexResultRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
634+
extension ComplexResultRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
632635
var jsValue: JSValue {
633636
return .object(JSObject(id: UInt32(bitPattern: _bjs_ComplexResultRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
634637
}
638+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
639+
_bjs_ComplexResultRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
640+
}
635641
}
636642

637643
#if arch(wasm32)
@@ -688,10 +694,13 @@ public func _bjs_StringRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> V
688694
#endif
689695
}
690696

691-
extension StringRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
697+
extension StringRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
692698
var jsValue: JSValue {
693699
return .object(JSObject(id: UInt32(bitPattern: _bjs_StringRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
694700
}
701+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
702+
_bjs_StringRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
703+
}
695704
}
696705

697706
#if arch(wasm32)
@@ -815,10 +824,13 @@ public func _bjs_OptionalReturnRoundtrip_deinit(_ pointer: UnsafeMutableRawPoint
815824
#endif
816825
}
817826

818-
extension OptionalReturnRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
827+
extension OptionalReturnRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
819828
var jsValue: JSValue {
820829
return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalReturnRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
821830
}
831+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
832+
_bjs_OptionalReturnRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
833+
}
822834
}
823835

824836
#if arch(wasm32)
@@ -982,10 +994,13 @@ public func _bjs_StructRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> V
982994
#endif
983995
}
984996

985-
extension StructRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
997+
extension StructRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
986998
var jsValue: JSValue {
987999
return .object(JSObject(id: UInt32(bitPattern: _bjs_StructRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
9881000
}
1001+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
1002+
_bjs_StructRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
1003+
}
9891004
}
9901005

9911006
#if arch(wasm32)
@@ -1126,10 +1141,13 @@ public func _bjs_SimpleClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Void
11261141
#endif
11271142
}
11281143

1129-
extension SimpleClass: ConvertibleToJSValue, _BridgedSwiftHeapObject {
1144+
extension SimpleClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
11301145
var jsValue: JSValue {
11311146
return .object(JSObject(id: UInt32(bitPattern: _bjs_SimpleClass_wrap(Unmanaged.passRetained(self).toOpaque()))))
11321147
}
1148+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
1149+
_bjs_SimpleClass_wrap(Unmanaged.passRetained(self).toOpaque())
1150+
}
11331151
}
11341152

11351153
#if arch(wasm32)
@@ -1228,10 +1246,13 @@ public func _bjs_AddressClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Void
12281246
#endif
12291247
}
12301248

1231-
extension AddressClass: ConvertibleToJSValue, _BridgedSwiftHeapObject {
1249+
extension AddressClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
12321250
var jsValue: JSValue {
12331251
return .object(JSObject(id: UInt32(bitPattern: _bjs_AddressClass_wrap(Unmanaged.passRetained(self).toOpaque()))))
12341252
}
1253+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
1254+
_bjs_AddressClass_wrap(Unmanaged.passRetained(self).toOpaque())
1255+
}
12351256
}
12361257

12371258
#if arch(wasm32)
@@ -1331,10 +1352,13 @@ public func _bjs_ClassRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo
13311352
#endif
13321353
}
13331354

1334-
extension ClassRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
1355+
extension ClassRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
13351356
var jsValue: JSValue {
13361357
return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
13371358
}
1359+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
1360+
_bjs_ClassRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
1361+
}
13381362
}
13391363

13401364
#if arch(wasm32)
@@ -1691,10 +1715,13 @@ public func _bjs_ArrayRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo
16911715
#endif
16921716
}
16931717

1694-
extension ArrayRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject {
1718+
extension ArrayRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
16951719
var jsValue: JSValue {
16961720
return .object(JSObject(id: UInt32(bitPattern: _bjs_ArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()))))
16971721
}
1722+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
1723+
_bjs_ArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())
1724+
}
16981725
}
16991726

17001727
#if arch(wasm32)

Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,13 @@ public func _bjs_PlayBridgeJS_deinit(_ pointer: UnsafeMutableRawPointer) -> Void
209209
#endif
210210
}
211211

212-
extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject {
212+
extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
213213
var jsValue: JSValue {
214214
return .object(JSObject(id: UInt32(bitPattern: _bjs_PlayBridgeJS_wrap(Unmanaged.passRetained(self).toOpaque()))))
215215
}
216+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
217+
_bjs_PlayBridgeJS_wrap(Unmanaged.passRetained(self).toOpaque())
218+
}
216219
}
217220

218221
#if arch(wasm32)

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,7 @@ public class ExportSwift {
167167
private func protocolCastSuffix(for returnType: BridgeType) -> (prefix: String, suffix: String) {
168168
switch returnType {
169169
case .swiftProtocol:
170-
return ("", " as! \(returnType.swiftType)")
171-
case .nullable(let wrappedType, _):
172-
if case .swiftProtocol = wrappedType {
173-
return ("(", ").flatMap { $0 as? \(wrappedType.swiftType) }")
174-
}
175-
return ("", "")
170+
return ("", " as! _BridgedSwiftProtocolExportable")
176171
default:
177172
return ("", "")
178173
}
@@ -311,6 +306,23 @@ public class ExportSwift {
311306
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
312307
append(stmt)
313308
}
309+
case .dictionary(.swiftProtocol):
310+
let stackCodegen = StackCodegen()
311+
for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") {
312+
append(stmt)
313+
}
314+
case .swiftProtocol:
315+
append("return ret.bridgeJSLowerAsProtocolReturn()")
316+
case .nullable(.swiftProtocol, _):
317+
append(
318+
"""
319+
if let ret {
320+
_swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())
321+
} else {
322+
_swift_js_return_optional_object(0, 0)
323+
}
324+
"""
325+
)
314326
default:
315327
append("return ret.bridgeJSLowerReturn()")
316328
}
@@ -703,10 +715,13 @@ public class ExportSwift {
703715
// If the class has an explicit access control, we need to add it to the extension declaration.
704716
let accessControl = klass.explicitAccessControl.map { "\($0) " } ?? ""
705717
let extensionDecl: DeclSyntax = """
706-
extension \(raw: klass.swiftCallName): ConvertibleToJSValue, _BridgedSwiftHeapObject {
718+
extension \(raw: klass.swiftCallName): ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
707719
\(raw: accessControl)var jsValue: JSValue {
708720
return .object(JSObject(id: UInt32(bitPattern: \(raw: wrapFunctionName)(Unmanaged.passRetained(self).toOpaque()))))
709721
}
722+
\(raw: accessControl)consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
723+
\(raw: wrapFunctionName)(Unmanaged.passRetained(self).toOpaque())
724+
}
710725
}
711726
"""
712727
// Build common function signature
@@ -781,7 +796,9 @@ struct StackCodegen {
781796
case .jsObject(_?):
782797
return ["\(raw: accessor).jsObject.bridgeJSStackPush()"]
783798
case .swiftProtocol:
784-
return ["(\(raw: accessor) as! \(raw: type.swiftType)).bridgeJSStackPush()"]
799+
return [
800+
"_swift_js_push_i32((\(raw: accessor) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())"
801+
]
785802
case .void, .namespaceEnum:
786803
return []
787804
case .array(let elementType):
@@ -798,14 +815,29 @@ struct StackCodegen {
798815
) -> [CodeBlockItemSyntax] {
799816
switch elementType {
800817
case .swiftProtocol:
801-
return ["\(raw: accessor).map { $0 as! \(raw: elementType.swiftType) }.bridgeJSStackPush()"]
818+
return lowerProtocolArrayStatements(accessor: accessor, varPrefix: varPrefix)
802819
case .void, .namespaceEnum:
803820
fatalError("Invalid array element type: \(elementType)")
804821
default:
805822
return ["\(raw: accessor).bridgeJSStackPush()"]
806823
}
807824
}
808825

826+
private func lowerProtocolArrayStatements(
827+
accessor: String,
828+
varPrefix: String
829+
) -> [CodeBlockItemSyntax] {
830+
var statements: [CodeBlockItemSyntax] = []
831+
let elemVar = "__bjs_elem_\(varPrefix)"
832+
statements.append("for \(raw: elemVar) in \(raw: accessor) {")
833+
statements.append(
834+
" _swift_js_push_i32((\(raw: elemVar) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())"
835+
)
836+
statements.append("}")
837+
statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))")
838+
return statements
839+
}
840+
809841
private func lowerDictionaryStatements(
810842
valueType: BridgeType,
811843
accessor: String,
@@ -815,7 +847,7 @@ struct StackCodegen {
815847
case .jsObject(let className?) where className != "JSObject":
816848
return ["\(raw: accessor).mapValues { $0.jsObject }.bridgeJSStackPush()"]
817849
case .swiftProtocol:
818-
return ["\(raw: accessor).mapValues { $0 as! \(raw: valueType.swiftType) }.bridgeJSStackPush()"]
850+
return lowerProtocolDictionaryStatements(accessor: accessor, varPrefix: varPrefix)
819851
case .nullable, .closure:
820852
return lowerDictionaryStatementsInline(
821853
valueType: valueType,
@@ -862,6 +894,22 @@ struct StackCodegen {
862894
statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))")
863895
return statements
864896
}
897+
898+
private func lowerProtocolDictionaryStatements(
899+
accessor: String,
900+
varPrefix: String
901+
) -> [CodeBlockItemSyntax] {
902+
var statements: [CodeBlockItemSyntax] = []
903+
let pairVar = "__bjs_kv_\(varPrefix)"
904+
statements.append("for \(raw: pairVar) in \(raw: accessor) {")
905+
statements.append(" \(raw: pairVar).key.bridgeJSStackPush()")
906+
statements.append(
907+
" _swift_js_push_i32((\(raw: pairVar).value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())"
908+
)
909+
statements.append("}")
910+
statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))")
911+
return statements
912+
}
865913
}
866914

867915
// MARK: - EnumCodegen

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,13 @@ public func _bjs_Item_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
414414
#endif
415415
}
416416

417-
extension Item: ConvertibleToJSValue, _BridgedSwiftHeapObject {
417+
extension Item: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
418418
var jsValue: JSValue {
419419
return .object(JSObject(id: UInt32(bitPattern: _bjs_Item_wrap(Unmanaged.passRetained(self).toOpaque()))))
420420
}
421+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
422+
_bjs_Item_wrap(Unmanaged.passRetained(self).toOpaque())
423+
}
421424
}
422425

423426
#if arch(wasm32)
@@ -477,10 +480,13 @@ public func _bjs_MultiArrayContainer_deinit(_ pointer: UnsafeMutableRawPointer)
477480
#endif
478481
}
479482

480-
extension MultiArrayContainer: ConvertibleToJSValue, _BridgedSwiftHeapObject {
483+
extension MultiArrayContainer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
481484
var jsValue: JSValue {
482485
return .object(JSObject(id: UInt32(bitPattern: _bjs_MultiArrayContainer_wrap(Unmanaged.passRetained(self).toOpaque()))))
483486
}
487+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
488+
_bjs_MultiArrayContainer_wrap(Unmanaged.passRetained(self).toOpaque())
489+
}
484490
}
485491

486492
#if arch(wasm32)

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ public func _bjs_FunctionA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
5252
#endif
5353
}
5454

55-
extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject {
55+
extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
5656
var jsValue: JSValue {
5757
return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque()))))
5858
}
59+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
60+
_bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque())
61+
}
5962
}
6063

6164
#if arch(wasm32)
@@ -112,10 +115,13 @@ public func _bjs_FunctionB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
112115
#endif
113116
}
114117

115-
extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject {
118+
extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
116119
var jsValue: JSValue {
117120
return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque()))))
118121
}
122+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
123+
_bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque())
124+
}
119125
}
120126

121127
#if arch(wasm32)

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,13 @@ public func _bjs_FunctionB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
5151
#endif
5252
}
5353

54-
extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject {
54+
extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
5555
var jsValue: JSValue {
5656
return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque()))))
5757
}
58+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
59+
_bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque())
60+
}
5861
}
5962

6063
#if arch(wasm32)
@@ -112,10 +115,13 @@ public func _bjs_FunctionA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
112115
#endif
113116
}
114117

115-
extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject {
118+
extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
116119
var jsValue: JSValue {
117120
return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque()))))
118121
}
122+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
123+
_bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque())
124+
}
119125
}
120126

121127
#if arch(wasm32)

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ public func _bjs_ClassA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
2929
#endif
3030
}
3131

32-
extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject {
32+
extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
3333
var jsValue: JSValue {
3434
return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque()))))
3535
}
36+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
37+
_bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque())
38+
}
3639
}
3740

3841
#if arch(wasm32)
@@ -68,10 +71,13 @@ public func _bjs_ClassB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
6871
#endif
6972
}
7073

71-
extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject {
74+
extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
7275
var jsValue: JSValue {
7376
return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque()))))
7477
}
78+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
79+
_bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque())
80+
}
7581
}
7682

7783
#if arch(wasm32)

0 commit comments

Comments
 (0)