diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9e90c175..7f4f6c87e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -163,7 +163,7 @@ jobs: # which collapses the wall-clock time from ~1h to that of the slowest single example. build-examples: if: github.event_name == 'pull_request' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -196,7 +196,7 @@ jobs: # main: build all examples in release and publish them to GitHub Pages. build-examples-deploy: if: github.event_name == 'push' && github.ref == 'refs/heads/main' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v7 - uses: ./.github/actions/install-swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 686f8d1e0..d882aad1c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1809,6 +1809,7 @@ public struct BridgeJSLink { body.write("const \(returnVariable) = \(call);") fragmentArguments = [returnVariable] } + body.write(lines: checkExceptionLines()) let liftedValues = try liftingFragment.printCode(fragmentArguments, context) assert(liftedValues.count <= 1, "Lifting fragment should produce at most one value") return liftedValues.first @@ -1818,10 +1819,11 @@ public struct BridgeJSLink { let call = "\(JSGlueVariableScope.reservedInstance).exports.\(abiName)(\(parameterForwardings.joined(separator: ", ")))" body.write("const ret = \(call);") + body.write(lines: checkExceptionLines()) return "ret" } - func checkExceptionLines() -> [String] { + private func checkExceptionLines() -> [String] { guard effects.isThrows else { return [] } @@ -1837,10 +1839,9 @@ public struct BridgeJSLink { ] } - /// Renders the thunk body (body code, exception handling, and optional return) into a printer. + /// Renders the thunk body and optional return; `call`/`callConstructor` put the exception check in `body`. func renderFunctionBody(into printer: CodeFragmentPrinter, returnExpr: String?) { printer.write(contentsOf: body) - printer.write(lines: checkExceptionLines()) if let returnExpr = returnExpr { printer.write("return \(returnExpr);") } @@ -3490,7 +3491,6 @@ extension BridgeJSLink { getterPrinter.write("get \(property.resolvedJSName)() {") getterPrinter.indent { getterPrinter.write(contentsOf: getterThunkBuilder.body) - getterPrinter.write(lines: getterThunkBuilder.checkExceptionLines()) if let returnExpr = getterReturnExpr { getterPrinter.write("return \(returnExpr);") } @@ -3517,7 +3517,6 @@ extension BridgeJSLink { setterPrinter.write("set \(property.resolvedJSName)(\(setterThunkBuilder.parameterList)) {") setterPrinter.indent { setterPrinter.write(contentsOf: setterThunkBuilder.body) - setterPrinter.write(lines: setterThunkBuilder.checkExceptionLines()) } setterPrinter.write("},") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift index 106f30761..670cb29fc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift @@ -107,6 +107,11 @@ import JavaScriptKit @JS func loadLabel(_ key: String) async throws(JSException) -> String { return try await delegate.loadLabel(key) } + + @JS func validatedDelegate() throws(JSException) -> MyViewControllerDelegate { + _ = try delegate.validate(0) + return delegate + } } // Protocol array support diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json index 4fbec6b49..40aa34cdf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json @@ -286,6 +286,23 @@ } } + }, + { + "abiName" : "bjs_MyViewController_validatedDelegate", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "validatedDelegate", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "MyViewControllerDelegate" + } + } } ], "name" : "MyViewController", diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index 3c4ba2a78..2f75db462 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1257,6 +1257,32 @@ public func _bjs_MyViewController_loadLabel(_ _self: UnsafeMutableRawPointer, _ #endif } +@_expose(wasm, "bjs_MyViewController_validatedDelegate") +@_cdecl("bjs_MyViewController_validatedDelegate") +public func _bjs_MyViewController_validatedDelegate(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let _self = MyViewController.bridgeJSLiftParameter(_self) + do { + let ret = _bridgeJSUnwrapProtocolExportable(try _self.validatedDelegate(), "MyViewControllerDelegate") + return ret.bridgeJSLowerAsProtocolReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MyViewController_delegate_get") @_cdecl("bjs_MyViewController_delegate_get") public func _bjs_MyViewController_delegate_get(_ _self: UnsafeMutableRawPointer) -> Int32 { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 33c4ff195..6cc51f282 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -944,26 +944,26 @@ export async function createInstantiator(options, swift) { asyncRoundTripStructThrows: function bjs_asyncRoundTripStructThrows(v) { structHelpers.M10TestModuleT10AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripStructThrows(); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }, asyncThrowsZeroArg: function bjs_asyncThrowsZeroArg() { const ret = instance.exports.bjs_asyncThrowsZeroArg(); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }, asyncCombineStructs: function bjs_asyncCombineStructs(a, b) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 4bfce3e14..2f45f8eed 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -755,14 +755,14 @@ export async function createInstantiator(options, swift) { const exports = { makeFoo: function bjs_makeFoo() { const ret = instance.exports.bjs_makeFoo(); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }, processFooArray: function bjs_processFooArray(foos) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts index e9b099f70..4259fb347 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts @@ -93,6 +93,7 @@ export interface MyViewController extends SwiftHeapObject { sendHelper(helper: Helper): void; validateValue(value: number): number; loadLabel(key: string): Promise; + validatedDelegate(): MyViewControllerDelegate; delegate: MyViewControllerDelegate; secondDelegate: MyViewControllerDelegate | null; } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index f07007c79..8802e8786 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -1363,14 +1363,26 @@ export async function createInstantiator(options, swift) { const keyBytes = textEncoder.encode(key); const keyId = swift.memory.retain(keyBytes); const ret = instance.exports.bjs_MyViewController_loadLabel(this.pointer, keyId, keyBytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); + return ret1; + } + validatedDelegate() { + const ret = instance.exports.bjs_MyViewController_validatedDelegate(this.pointer); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; } get delegate() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index d6fa6f143..a9730573c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -248,14 +248,14 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModule10RenderableP_10RenderableP = function(param0) { const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(boxPtr, swift.memory.retain(param0)); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_10RenderableP); @@ -273,14 +273,14 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModule10RenderableP_SS"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModule10RenderableP_SS = function(param0) { instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_SS(boxPtr, swift.memory.retain(param0)); - const ret = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret = tmpRetString; + tmpRetString = undefined; return ret; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_SS); @@ -305,14 +305,14 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(boxPtr, +isSome, result); - const ret = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret = tmpRetString; + tmpRetString = undefined; return ret; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10RenderableP_SS); @@ -330,14 +330,14 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuley_10RenderableP"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuley_10RenderableP = function() { const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuley_10RenderableP(boxPtr); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuley_10RenderableP); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index f56929d7c..3f4ab6e05 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -751,14 +751,14 @@ export async function createInstantiator(options, swift) { const param0Bytes = textEncoder.encode(param0); const param0Id = swift.memory.retain(param0Bytes); instance.exports.invoke_swift_closure_TestModule_10TestModule5ThemeO_5ThemeO(boxPtr, param0Id, param0Bytes.length); - const ret = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret = tmpRetString; + tmpRetString = undefined; return ret; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule5ThemeO_5ThemeO); @@ -777,13 +777,13 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModule6AnimalV_6AnimalV = function(param0) { structHelpers.M10TestModuleT6Animal.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV(boxPtr); - const structValue = structHelpers.M10TestModuleT6Animal.lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const structValue = structHelpers.M10TestModuleT6Animal.lift(); return structValue; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule6AnimalV_6AnimalV); @@ -826,13 +826,13 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModule9APIResultO_9APIResultO = function(param0) { const param0CaseId = enumHelpers.M10TestModuleT9APIResult.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModule9APIResultO_9APIResultO(boxPtr, param0CaseId); - const ret = enumHelpers.M10TestModuleT9APIResult.lift(i32Stack.pop()); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret = enumHelpers.M10TestModuleT9APIResult.lift(i32Stack.pop()); return ret; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule9APIResultO_9APIResultO); @@ -928,14 +928,14 @@ export async function createInstantiator(options, swift) { const param0Bytes = textEncoder.encode(param0); const param0Id = swift.memory.retain(param0Bytes); instance.exports.invoke_swift_closure_TestModule_10TestModuleSS_SS(boxPtr, param0Id, param0Bytes.length); - const ret = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret = tmpRetString; + tmpRetString = undefined; return ret; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSS_SS); @@ -1046,14 +1046,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10HttpStatusO = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10HttpStatusO(boxPtr, +isSome, isSome ? param0 : 0); - const optResult = tmpRetOptionalInt; - tmpRetOptionalInt = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10HttpStatusO); @@ -1089,14 +1089,14 @@ export async function createInstantiator(options, swift) { result1 = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(boxPtr, +isSome, result, result1); - const optResult = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetString; + tmpRetString = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO); @@ -1115,13 +1115,13 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV = function(param0) { __bjs_codec_Optional_M10TestModuleT6Animal.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(boxPtr); - const optValue = __bjs_codec_Optional_M10TestModuleT6Animal.lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optValue = __bjs_codec_Optional_M10TestModuleT6Animal.lift(); return optValue; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV); @@ -1146,15 +1146,15 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC(boxPtr, +isSome, result); - const pointer = tmpRetOptionalHeapObject; - tmpRetOptionalHeapObject = undefined; - const optResult = pointer === null ? null : _exports['Person'].__construct(pointer); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + const optResult = pointer === null ? null : _exports['Person'].__construct(pointer); return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6PersonC_Sq6PersonC); @@ -1192,14 +1192,14 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO(boxPtr, +isSome, result); - const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.M10TestModuleT9APIResult.lift(tag); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const tag = i32Stack.pop(); + const optResult = tag === -1 ? null : enumHelpers.M10TestModuleT9APIResult.lift(tag); return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO); @@ -1218,14 +1218,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSq9DirectionO_Sq9DirectionO = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSq9DirectionO_Sq9DirectionO(boxPtr, +isSome, isSome ? param0 : 0); - const optResult = tmpRetOptionalInt; - tmpRetOptionalInt = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq9DirectionO_Sq9DirectionO); @@ -1261,14 +1261,14 @@ export async function createInstantiator(options, swift) { result1 = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSS_SqSS(boxPtr, +isSome, result, result1); - const optResult = tmpRetString; - tmpRetString = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetString; + tmpRetString = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSS_SqSS); @@ -1287,14 +1287,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSqSb_SqSb = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSb_SqSb(boxPtr, +isSome, isSome ? param0 ? 1 : 0 : 0); - const optResult = tmpRetOptionalBool; - tmpRetOptionalBool = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalBool; + tmpRetOptionalBool = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSb_SqSb); @@ -1313,14 +1313,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSqSd_SqSd = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSd_SqSd(boxPtr, +isSome, isSome ? param0 : 0.0); - const optResult = tmpRetOptionalDouble; - tmpRetOptionalDouble = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSd_SqSd); @@ -1339,14 +1339,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSqSf_SqSf = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSf_SqSf(boxPtr, +isSome, isSome ? param0 : 0.0); - const optResult = tmpRetOptionalFloat; - tmpRetOptionalFloat = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSf_SqSf); @@ -1365,14 +1365,14 @@ export async function createInstantiator(options, swift) { const lower_closure_TestModule_10TestModuleSqSi_SqSi = function(param0) { const isSome = param0 != null; instance.exports.invoke_swift_closure_TestModule_10TestModuleSqSi_SqSi(boxPtr, +isSome, isSome ? param0 : 0); - const optResult = tmpRetOptionalInt; - tmpRetOptionalInt = undefined; if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; return optResult; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSi_SqSi); @@ -1393,14 +1393,14 @@ export async function createInstantiator(options, swift) { const param0Bytes = textEncoder.encode(param0); const param0Id = swift.memory.retain(param0Bytes); const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(boxPtr, param0Id, param0Bytes.length); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSS_SS); @@ -1418,14 +1418,14 @@ export async function createInstantiator(options, swift) { bjs["make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleYaKSb_9APIResultO = function(param0) { const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO(boxPtr, param0); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSb_9APIResultO); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index 3ba6f5c0f..b15678998 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -406,14 +406,14 @@ export async function createInstantiator(options, swift) { const param0Bytes = textEncoder.encode(param0); const param0Id = swift.memory.retain(param0Bytes); const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(boxPtr, param0Id, param0Bytes.length); - const ret1 = swift.memory.getObject(ret); - swift.memory.release(ret); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); return ret1; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSS_SS); diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 1429bb0fb..55ab78e7a 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -110,6 +110,12 @@ struct TestError: Error { @JS func throwsWithDoubleResult() throws(JSException) -> Double { return 1.0 } @JS func throwsWithSwiftHeapObjectResult() throws(JSException) -> Greeter { return Greeter(name: "Test") } @JS func throwsWithJSObjectResult() throws(JSException) -> JSObject { return JSObject() } +@JS func throwsBeforeJSObjectResult() throws(JSException) -> JSObject { + throw JSException(JSError(message: "JSObjectResultError").jsValue) +} +@JS func throwsBeforeProtocolResult() throws(JSException) -> DataProcessor { + throw JSException(JSError(message: "ProtocolResultError").jsValue) +} @JS func zeroArgAsyncThrows() async throws(JSException) -> String { throw JSException(JSError(message: "ZeroArgAsyncThrowsError").jsValue) diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index f2c868c84..3b82a15d5 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -10793,6 +10793,56 @@ public func _bjs_throwsWithJSObjectResult() -> Int32 { #endif } +@_expose(wasm, "bjs_throwsBeforeJSObjectResult") +@_cdecl("bjs_throwsBeforeJSObjectResult") +public func _bjs_throwsBeforeJSObjectResult() -> Int32 { + #if arch(wasm32) + do { + let ret = try throwsBeforeJSObjectResult() + return ret.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_throwsBeforeProtocolResult") +@_cdecl("bjs_throwsBeforeProtocolResult") +public func _bjs_throwsBeforeProtocolResult() -> Int32 { + #if arch(wasm32) + do { + let ret = _bridgeJSUnwrapProtocolExportable(try throwsBeforeProtocolResult(), "DataProcessor") + return ret.bridgeJSLowerAsProtocolReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_zeroArgAsyncThrows") @_cdecl("bjs_zeroArgAsyncThrows") public func _bjs_zeroArgAsyncThrows() -> Int32 { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 265fcf9cb..c4fd1d602 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -15971,6 +15971,40 @@ } } }, + { + "abiName" : "bjs_throwsBeforeJSObjectResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "throwsBeforeJSObjectResult", + "parameters" : [ + + ], + "returnType" : { + "jsObject" : { + + } + } + }, + { + "abiName" : "bjs_throwsBeforeProtocolResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "throwsBeforeProtocolResult", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, { "abiName" : "bjs_zeroArgAsyncThrows", "effects" : { diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 17b48679c..e1d856647 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -629,6 +629,9 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.fail("Expected no error"); } + assert.throws(() => exports.throwsBeforeJSObjectResult(), { name: "Error", message: "JSObjectResultError" }); + assert.throws(() => exports.throwsBeforeProtocolResult(), { name: "Error", message: "ProtocolResultError" }); + // Test enums assert.equal(exports.Direction.North, 0); assert.equal(exports.Direction.South, 1);