@@ -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
0 commit comments