Skip to content

Commit 4a290f6

Browse files
committed
BridgeJS: Check thrown errors before lifting return values
1 parent a0961dd commit 4a290f6

17 files changed

Lines changed: 5118 additions & 109 deletions

File tree

‎Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,7 @@ public struct BridgeJSLink {
18091809
body.write("const \(returnVariable) = \(call);")
18101810
fragmentArguments = [returnVariable]
18111811
}
1812+
body.write(lines: checkExceptionLines())
18121813
let liftedValues = try liftingFragment.printCode(fragmentArguments, context)
18131814
assert(liftedValues.count <= 1, "Lifting fragment should produce at most one value")
18141815
return liftedValues.first
@@ -1818,10 +1819,11 @@ public struct BridgeJSLink {
18181819
let call =
18191820
"\(JSGlueVariableScope.reservedInstance).exports.\(abiName)(\(parameterForwardings.joined(separator: ", ")))"
18201821
body.write("const ret = \(call);")
1822+
body.write(lines: checkExceptionLines())
18211823
return "ret"
18221824
}
18231825

1824-
func checkExceptionLines() -> [String] {
1826+
private func checkExceptionLines() -> [String] {
18251827
guard effects.isThrows else {
18261828
return []
18271829
}
@@ -1837,10 +1839,9 @@ public struct BridgeJSLink {
18371839
]
18381840
}
18391841

1840-
/// Renders the thunk body (body code, exception handling, and optional return) into a printer.
1842+
/// Renders the thunk body and optional return; `call`/`callConstructor` put the exception check in `body`.
18411843
func renderFunctionBody(into printer: CodeFragmentPrinter, returnExpr: String?) {
18421844
printer.write(contentsOf: body)
1843-
printer.write(lines: checkExceptionLines())
18441845
if let returnExpr = returnExpr {
18451846
printer.write("return \(returnExpr);")
18461847
}
@@ -3490,7 +3491,6 @@ extension BridgeJSLink {
34903491
getterPrinter.write("get \(property.resolvedJSName)() {")
34913492
getterPrinter.indent {
34923493
getterPrinter.write(contentsOf: getterThunkBuilder.body)
3493-
getterPrinter.write(lines: getterThunkBuilder.checkExceptionLines())
34943494
if let returnExpr = getterReturnExpr {
34953495
getterPrinter.write("return \(returnExpr);")
34963496
}
@@ -3517,7 +3517,6 @@ extension BridgeJSLink {
35173517
setterPrinter.write("set \(property.resolvedJSName)(\(setterThunkBuilder.parameterList)) {")
35183518
setterPrinter.indent {
35193519
setterPrinter.write(contentsOf: setterThunkBuilder.body)
3520-
setterPrinter.write(lines: setterThunkBuilder.checkExceptionLines())
35213520
}
35223521
setterPrinter.write("},")
35233522

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import JavaScriptKit
2+
3+
@JS protocol ThrowingDelegate {
4+
func notify()
5+
}
6+
7+
@JS class ThrowingBox {
8+
@JS init(value: Int) throws(JSException) {}
9+
10+
@JS func method() throws(JSException) -> JSObject {
11+
return JSObject()
12+
}
13+
14+
@JS static func staticMethod() throws(JSException) -> ThrowingBox {
15+
return try ThrowingBox(value: 0)
16+
}
17+
}
18+
19+
@JS struct ThrowingPoint {
20+
var x: Int
21+
22+
@JS func method() throws(JSException) -> JSObject {
23+
return JSObject()
24+
}
25+
26+
@JS static func staticMethod() throws(JSException) -> JSObject {
27+
return JSObject()
28+
}
29+
}
30+
31+
@JS enum ThrowingDirection {
32+
case north
33+
case south
34+
35+
@JS static func staticMethod() throws(JSException) -> JSObject {
36+
return JSObject()
37+
}
38+
}
39+
40+
@JS enum ThrowingTheme: String {
41+
case light
42+
case dark
43+
}
44+
45+
@JS enum ThrowingPayload {
46+
case value(Int)
47+
case message(String)
48+
}
49+
50+
@JS enum ThrowingNamespace {
51+
@JS static func namespaced() throws(JSException) -> JSObject {
52+
return JSObject()
53+
}
54+
}
55+
56+
@JS func throwingVoid() throws(JSException) {}
57+
@JS func throwingInt() throws(JSException) -> Int { 0 }
58+
@JS func throwingString() throws(JSException) -> String { "" }
59+
@JS func throwingJSObject() throws(JSException) -> JSObject { JSObject() }
60+
@JS func throwingOptionalJSObject() throws(JSException) -> JSObject? { nil }
61+
@JS func throwingJSValue() throws(JSException) -> JSValue { .undefined }
62+
@JS func throwingProtocol() throws(JSException) -> ThrowingDelegate { fatalError() }
63+
@JS func throwingClass() throws(JSException) -> ThrowingBox { try ThrowingBox(value: 0) }
64+
@JS func throwingOptionalClass() throws(JSException) -> ThrowingBox? { nil }
65+
@JS func throwingClosure() throws(JSException) -> (Int) -> Int { { $0 } }
66+
@JS func throwingStruct() throws(JSException) -> ThrowingPoint { ThrowingPoint(x: 0) }
67+
@JS func throwingCaseEnum() throws(JSException) -> ThrowingDirection { .north }
68+
@JS func throwingRawValueEnum() throws(JSException) -> ThrowingTheme { .light }
69+
@JS func throwingAssociatedValueEnum() throws(JSException) -> ThrowingPayload { .value(0) }
70+
@JS func throwingArray() throws(JSException) -> [Int] { [] }
71+
@JS func throwingDictionary() throws(JSException) -> [String: Int] { [:] }
72+
@JS func throwingAsync() async throws(JSException) -> JSObject { JSObject() }

0 commit comments

Comments
 (0)