Skip to content

Commit f2bf525

Browse files
BridgeJS: Support @JS class in imported function signatures (#601)
1 parent d9adac0 commit f2bf525

File tree

13 files changed

+153
-44
lines changed

13 files changed

+153
-44
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -957,18 +957,8 @@ extension BridgeType {
957957
return LoweringParameterInfo(loweredParameters: [("funcRef", .i32)])
958958
case .unsafePointer:
959959
return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)])
960-
case .swiftHeapObject(let className):
961-
switch context {
962-
case .importTS:
963-
throw BridgeJSCoreError(
964-
"""
965-
swiftHeapObject '\(className)' is not supported in TypeScript imports.
966-
Swift classes can only be used in @JS protocols where Swift owns the instance.
967-
"""
968-
)
969-
case .exportSwift:
970-
return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)])
971-
}
960+
case .swiftHeapObject:
961+
return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)])
972962
case .swiftProtocol:
973963
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
974964
case .caseEnum:
@@ -1038,18 +1028,8 @@ extension BridgeType {
10381028
return LiftingReturnInfo(valueToLift: .i32)
10391029
case .unsafePointer:
10401030
return LiftingReturnInfo(valueToLift: .pointer)
1041-
case .swiftHeapObject(let className):
1042-
switch context {
1043-
case .importTS:
1044-
throw BridgeJSCoreError(
1045-
"""
1046-
swiftHeapObject '\(className)' cannot be returned from imported TypeScript functions.
1047-
JavaScript cannot create Swift heap objects.
1048-
"""
1049-
)
1050-
case .exportSwift:
1051-
return LiftingReturnInfo(valueToLift: .pointer)
1052-
}
1031+
case .swiftHeapObject:
1032+
return LiftingReturnInfo(valueToLift: .pointer)
10531033
case .swiftProtocol:
10541034
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
10551035
case .caseEnum:

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ struct IntrinsicJSFragment: Sendable {
581581
return IntrinsicJSFragment(
582582
parameters: ["pointer"],
583583
printCode: { arguments, scope, printer, cleanupCode in
584-
return ["\(name).__construct(\(arguments[0]))"]
584+
return ["_exports['\(name)'].__construct(\(arguments[0]))"]
585585
}
586586
)
587587
}
@@ -1985,14 +1985,7 @@ struct IntrinsicJSFragment: Sendable {
19851985
case .jsValue: return .jsValueLiftParameter
19861986
case .unsafePointer: return .identity
19871987
case .swiftHeapObject(let name):
1988-
switch context {
1989-
case .importTS:
1990-
throw BridgeJSLinkError(
1991-
message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)"
1992-
)
1993-
case .exportSwift:
1994-
return .swiftHeapObjectLiftParameter(name)
1995-
}
1988+
return .swiftHeapObjectLiftParameter(name)
19961989
case .swiftProtocol: return .jsObjectLiftParameter
19971990
case .void:
19981991
throw BridgeJSLinkError(
@@ -2074,15 +2067,8 @@ struct IntrinsicJSFragment: Sendable {
20742067
case .jsObject: return .jsObjectLowerReturn
20752068
case .jsValue: return .jsValueLowerReturn(context: context)
20762069
case .unsafePointer: return .identity
2077-
case .swiftHeapObject(let name):
2078-
switch context {
2079-
case .importTS:
2080-
throw BridgeJSLinkError(
2081-
message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)"
2082-
)
2083-
case .exportSwift:
2084-
return .swiftHeapObjectLowerReturn
2085-
}
2070+
case .swiftHeapObject:
2071+
return .swiftHeapObjectLowerReturn
20862072
case .swiftProtocol: return .jsObjectLowerReturn
20872073
case .void: return .void
20882074
case .nullable(let wrappedType, let kind):

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@
1818

1919
@JS public class PublicGreeter {}
2020
@JS package class PackageGreeter {}
21+
22+
@JSFunction func jsRoundTripGreeter(greeter: Greeter) throws(JSException) -> Greeter

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,34 @@
141141

142142
]
143143
},
144+
"imported" : {
145+
"children" : [
146+
{
147+
"functions" : [
148+
{
149+
"name" : "jsRoundTripGreeter",
150+
"parameters" : [
151+
{
152+
"name" : "greeter",
153+
"type" : {
154+
"swiftHeapObject" : {
155+
"_0" : "Greeter"
156+
}
157+
}
158+
}
159+
],
160+
"returnType" : {
161+
"swiftHeapObject" : {
162+
"_0" : "Greeter"
163+
}
164+
}
165+
}
166+
],
167+
"types" : [
168+
169+
]
170+
}
171+
]
172+
},
144173
"moduleName" : "TestModule"
145174
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,22 @@ fileprivate func _bjs_PackageGreeter_wrap(_ pointer: UnsafeMutableRawPointer) ->
134134
fileprivate func _bjs_PackageGreeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 {
135135
fatalError("Only available on WebAssembly")
136136
}
137-
#endif
137+
#endif
138+
139+
#if arch(wasm32)
140+
@_extern(wasm, module: "TestModule", name: "bjs_jsRoundTripGreeter")
141+
fileprivate func bjs_jsRoundTripGreeter(_ greeter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer
142+
#else
143+
fileprivate func bjs_jsRoundTripGreeter(_ greeter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
144+
fatalError("Only available on WebAssembly")
145+
}
146+
#endif
147+
148+
func _$jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter {
149+
let greeterPointer = greeter.bridgeJSLowerParameter()
150+
let ret = bjs_jsRoundTripGreeter(greeterPointer)
151+
if let error = _swift_js_take_exception() {
152+
throw error
153+
}
154+
return Greeter.bridgeJSLiftReturn(ret)
155+
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ export async function createInstantiator(options, swift) {
513513
}
514514
TestModule["bjs_MyViewControllerDelegate_onHelperUpdated"] = function bjs_MyViewControllerDelegate_onHelperUpdated(self, helper) {
515515
try {
516-
swift.memory.getObject(self).onHelperUpdated(Helper.__construct(helper));
516+
swift.memory.getObject(self).onHelperUpdated(_exports['Helper'].__construct(helper));
517517
} catch (error) {
518518
setException(error);
519519
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type Exports = {
3131
takeGreeter(greeter: Greeter): void;
3232
}
3333
export type Imports = {
34+
jsRoundTripGreeter(greeter: Greeter): Greeter;
3435
}
3536
export function createInstantiator(options: {
3637
imports: Imports;

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export async function createInstantiator(options, swift) {
3838
addImports: (importObject, importsContext) => {
3939
bjs = {};
4040
importObject["bjs"] = bjs;
41+
const imports = options.getImports(importsContext);
4142
bjs["swift_js_return_string"] = function(ptr, len) {
4243
const bytes = new Uint8Array(memory.buffer, ptr, len);
4344
tmpRetString = textDecoder.decode(bytes);
@@ -214,6 +215,16 @@ export async function createInstantiator(options, swift) {
214215
const obj = PublicGreeter.__construct(pointer);
215216
return swift.memory.retain(obj);
216217
};
218+
const TestModule = importObject["TestModule"] = importObject["TestModule"] || {};
219+
TestModule["bjs_jsRoundTripGreeter"] = function bjs_jsRoundTripGreeter(greeter) {
220+
try {
221+
let ret = imports.jsRoundTripGreeter(_exports['Greeter'].__construct(greeter));
222+
return ret.pointer;
223+
} catch (error) {
224+
setException(error);
225+
return 0
226+
}
227+
}
217228
},
218229
setInstance: (i) => {
219230
instance = i;

Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10666,4 +10666,22 @@ func _$jsRoundTripOptionalStringUndefined(_ name: JSUndefinedOr<String>) throws(
1066610666
throw error
1066710667
}
1066810668
return JSUndefinedOr<String>.bridgeJSLiftReturnFromSideChannel()
10669+
}
10670+
10671+
#if arch(wasm32)
10672+
@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftClassSupportImports_jsRoundTripGreeter_static")
10673+
fileprivate func bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(_ greeter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer
10674+
#else
10675+
fileprivate func bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(_ greeter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
10676+
fatalError("Only available on WebAssembly")
10677+
}
10678+
#endif
10679+
10680+
func _$SwiftClassSupportImports_jsRoundTripGreeter(_ greeter: Greeter) throws(JSException) -> Greeter {
10681+
let greeterPointer = greeter.bridgeJSLowerParameter()
10682+
let ret = bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(greeterPointer)
10683+
if let error = _swift_js_take_exception() {
10684+
throw error
10685+
}
10686+
return Greeter.bridgeJSLiftReturn(ret)
1066910687
}

Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15310,6 +15310,45 @@
1531015310
"types" : [
1531115311

1531215312
]
15313+
},
15314+
{
15315+
"functions" : [
15316+
15317+
],
15318+
"types" : [
15319+
{
15320+
"getters" : [
15321+
15322+
],
15323+
"methods" : [
15324+
15325+
],
15326+
"name" : "SwiftClassSupportImports",
15327+
"setters" : [
15328+
15329+
],
15330+
"staticMethods" : [
15331+
{
15332+
"name" : "jsRoundTripGreeter",
15333+
"parameters" : [
15334+
{
15335+
"name" : "greeter",
15336+
"type" : {
15337+
"swiftHeapObject" : {
15338+
"_0" : "Greeter"
15339+
}
15340+
}
15341+
}
15342+
],
15343+
"returnType" : {
15344+
"swiftHeapObject" : {
15345+
"_0" : "Greeter"
15346+
}
15347+
}
15348+
}
15349+
]
15350+
}
15351+
]
1531315352
}
1531415353
]
1531515354
},

0 commit comments

Comments
 (0)