diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 9402cdd9d..db900cf99 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -668,7 +668,7 @@ struct IntrinsicJSFragment: Sendable { resultExpr = "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : \(absenceLiteral)" case .swiftHeapObject(let name): - resultExpr = "\(isSome) ? \(name).__construct(\(wrappedValue)) : \(absenceLiteral)" + resultExpr = "\(isSome) ? _exports['\(name)'].__construct(\(wrappedValue)) : \(absenceLiteral)" case .jsObject: resultExpr = "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : \(absenceLiteral)" @@ -1120,6 +1120,8 @@ struct IntrinsicJSFragment: Sendable { scope.emitPushF64Parameter(payload2Var, printer: printer) } scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) + case .swiftHeapObject: + printer.write("return \(isSomeVar) ? \(value).pointer : 0;") case .array(let elementType): printer.write("if (\(isSomeVar)) {") try printer.indent { @@ -1230,7 +1232,9 @@ struct IntrinsicJSFragment: Sendable { printer.write("}") scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) default: - () + throw BridgeJSLinkError( + message: "Unsupported wrapped type for returning from JS function: \(wrappedType)" + ) } return [] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index aa520783a..d7b5a5b8e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -20,3 +20,4 @@ @JS package class PackageGreeter {} @JSFunction func jsRoundTripGreeter(greeter: Greeter) throws(JSException) -> Greeter +@JSFunction func jsRoundTripOptionalGreeter(greeter: Greeter?) throws(JSException) -> Greeter? diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index d1bf42cff..7cebdd5e6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -162,6 +162,34 @@ "_0" : "Greeter" } } + }, + { + "name" : "jsRoundTripOptionalGreeter", + "parameters" : [ + { + "name" : "greeter", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } } ], "types" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 581d6f1c0..ca82b87c4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -152,4 +152,22 @@ func _$jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter { throw error } return Greeter.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_jsRoundTripOptionalGreeter") +fileprivate func bjs_jsRoundTripOptionalGreeter(_ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer +#else +fileprivate func bjs_jsRoundTripOptionalGreeter(_ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + fatalError("Only available on WebAssembly") +} +#endif + +func _$jsRoundTripOptionalGreeter(_ greeter: Optional) throws(JSException) -> Optional { + let (greeterIsSome, greeterPointer) = greeter.bridgeJSLowerParameter() + let ret = bjs_jsRoundTripOptionalGreeter(greeterIsSome, greeterPointer) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 00b9626e3..fd37c7178 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -529,7 +529,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_MyViewControllerDelegate_onOptionalHelperUpdated"] = function bjs_MyViewControllerDelegate_onOptionalHelperUpdated(self, helperIsSome, helperWrappedValue) { try { - swift.memory.getObject(self).onOptionalHelperUpdated(helperIsSome ? Helper.__construct(helperWrappedValue) : null); + swift.memory.getObject(self).onOptionalHelperUpdated(helperIsSome ? _exports['Helper'].__construct(helperWrappedValue) : null); } catch (error) { setException(error); } @@ -538,6 +538,7 @@ export async function createInstantiator(options, swift) { try { let ret = swift.memory.getObject(self).createOptionalHelper(); const isSome = ret != null; + return isSome ? ret.pointer : 0; } catch (error) { setException(error); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index d3461f8c1..05fc97fee 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -32,6 +32,7 @@ export type Exports = { } export type Imports = { jsRoundTripGreeter(greeter: Greeter): Greeter; + jsRoundTripOptionalGreeter(greeter: Greeter | null): Greeter | null; } export function createInstantiator(options: { imports: Imports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index eaa5d7720..13ea6ba75 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -225,6 +225,15 @@ export async function createInstantiator(options, swift) { return 0 } } + TestModule["bjs_jsRoundTripOptionalGreeter"] = function bjs_jsRoundTripOptionalGreeter(greeterIsSome, greeterWrappedValue) { + try { + let ret = imports.jsRoundTripOptionalGreeter(greeterIsSome ? _exports['Greeter'].__construct(greeterWrappedValue) : null); + const isSome = ret != null; + return isSome ? ret.pointer : 0; + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 1feb3eed6..b10a82fdf 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -10677,6 +10677,15 @@ fileprivate func bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(_ greete } #endif +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static") +fileprivate func bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static(_ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer +#else +fileprivate func bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static(_ greeterIsSome: Int32, _ greeterPointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + fatalError("Only available on WebAssembly") +} +#endif + func _$SwiftClassSupportImports_jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter { let greeterPointer = greeter.bridgeJSLowerParameter() let ret = bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(greeterPointer) @@ -10684,4 +10693,13 @@ func _$SwiftClassSupportImports_jsRoundTripGreeter(_ greeter: Greeter) throws(JS throw error } return Greeter.bridgeJSLiftReturn(ret) +} + +func _$SwiftClassSupportImports_jsRoundTripOptionalGreeter(_ greeter: Optional) throws(JSException) -> Optional { + let (greeterIsSome, greeterPointer) = greeter.bridgeJSLowerParameter() + let ret = bjs_SwiftClassSupportImports_jsRoundTripOptionalGreeter_static(greeterIsSome, greeterPointer) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index de7ab4a5d..7e2d4d855 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -15345,6 +15345,34 @@ "_0" : "Greeter" } } + }, + { + "name" : "jsRoundTripOptionalGreeter", + "parameters" : [ + { + "name" : "greeter", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } } ] } diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs index fdb5d498d..0368cb74a 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs @@ -6,5 +6,8 @@ export function getImports(importsContext) { jsRoundTripGreeter: (greeter) => { return greeter; }, + jsRoundTripOptionalGreeter: (greeter) => { + return greeter; + }, }; } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift b/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift index 3cee17554..1a3dd0a4f 100644 --- a/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/SwiftClassSupportTests.swift @@ -3,6 +3,7 @@ import XCTest @JSClass struct SwiftClassSupportImports { @JSFunction static func jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter + @JSFunction static func jsRoundTripOptionalGreeter(_ greeter: Greeter?) throws(JSException) -> Greeter? } final class SwiftClassSupportTests: XCTestCase { @@ -10,4 +11,12 @@ final class SwiftClassSupportTests: XCTestCase { let greeter = try SwiftClassSupportImports.jsRoundTripGreeter(Greeter(name: "Hello")) XCTAssertEqual(greeter.name, "Hello") } + + func testRoundTripOptionalGreeter() throws { + let greeter1 = try SwiftClassSupportImports.jsRoundTripOptionalGreeter(nil) + XCTAssertNil(greeter1) + + let greeter2 = try SwiftClassSupportImports.jsRoundTripOptionalGreeter(Greeter(name: "Hello")) + XCTAssertEqual(greeter2?.name, "Hello") + } }