Skip to content

Commit 3b6276d

Browse files
committed
BridgeJS: Support generic functions at the Swift and JavaScript boundary
1 parent bc356b5 commit 3b6276d

15 files changed

Lines changed: 1298 additions & 42 deletions

File tree

Plugins/BridgeJS/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ graph LR
9898
| `Dictionary<K, V>` | `Record<K, V>` | - | [#495](https://github.com/swiftwasm/JavaScriptKit/issues/495) |
9999
| `Set<T>` | `Set<T>` | - | [#397](https://github.com/swiftwasm/JavaScriptKit/issues/397) |
100100
| `Foundation.URL` | `string` | - | [#496](https://github.com/swiftwasm/JavaScriptKit/issues/496) |
101-
| Generics | - | - | [#398](https://github.com/swiftwasm/JavaScriptKit/issues/398) |
101+
| Generic top-level function (`T`, `[T]`, `T?`, `[String: T]`) | `<T>(value: T, type: BridgeType<T>)` | Depends on `T` | |
102102

103103
### Import-specific (TypeScript -> Swift)
104104

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 306 additions & 3 deletions
Large diffs are not rendered by default.

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ public struct ImportTS {
143143
}
144144

145145
func lowerParameter(param: Parameter) throws {
146+
if let genericPush = param.type.genericStackPushStatement(value: param.name) {
147+
stackLoweringStmts.insert(genericPush, at: 0)
148+
return
149+
}
150+
146151
let loweringInfo = try param.type.loweringParameterInfo(context: context)
147152

148153
switch param.type {
@@ -241,6 +246,12 @@ public struct ImportTS {
241246
abiParameterForwardings.insert(contentsOf: ["resolveRef", "rejectRef"], at: 0)
242247
}
243248

249+
func appendTypeIDParameter(index: Int, genericParameterName: String) {
250+
let abiParamName = "_generic\(index)TypeId"
251+
abiParameterSignatures.append((abiParamName, .i32))
252+
abiParameterForwardings.append("\(genericParameterName).bridgeJSTypeID")
253+
}
254+
244255
func call() throws {
245256
for stmt in stackLoweringStmts {
246257
body.write(stmt.description)
@@ -297,14 +308,18 @@ public struct ImportTS {
297308
body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()")
298309
} else {
299310
let liftExpr: String
300-
switch returnType {
301-
case .closure(let signature, _):
302-
liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)"
303-
default:
304-
if liftingInfo.valueToLift != nil {
305-
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)"
306-
} else {
307-
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()"
311+
if let genericPop = returnType.genericStackPopExpression {
312+
liftExpr = genericPop
313+
} else {
314+
switch returnType {
315+
case .closure(let signature, _):
316+
liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)"
317+
default:
318+
if liftingInfo.valueToLift != nil {
319+
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)"
320+
} else {
321+
liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()"
322+
}
308323
}
309324
}
310325
body.write("return \(liftExpr)")
@@ -363,7 +378,8 @@ public struct ImportTS {
363378
name: String,
364379
parameters: [Parameter],
365380
returnType: BridgeType,
366-
effects: Effects
381+
effects: Effects,
382+
genericParameters: [String] = []
367383
) -> DeclSyntax {
368384
let printer = CodeFragmentPrinter()
369385
let signature = SwiftSignatureBuilder.buildFunctionSignature(
@@ -372,7 +388,12 @@ public struct ImportTS {
372388
effects: effects,
373389
useWildcardLabels: true
374390
)
375-
printer.write("func \(name.backtickIfNeeded())\(signature) {")
391+
let genericClause =
392+
genericParameters.isEmpty
393+
? ""
394+
: "<" + genericParameters.map { "\($0): _BridgedSwiftGenericBridgeable" }.joined(separator: ", ")
395+
+ ">"
396+
printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {")
376397
printer.indent {
377398
printer.write(lines: body.lines)
378399
}
@@ -432,6 +453,9 @@ public struct ImportTS {
432453
for param in function.parameters {
433454
try builder.lowerParameter(param: param)
434455
}
456+
for (index, genericParam) in (function.genericParameters ?? []).enumerated() {
457+
builder.appendTypeIDParameter(index: index, genericParameterName: genericParam)
458+
}
435459
try builder.call()
436460
try builder.liftReturnValue()
437461
topLevelDecls.append(builder.renderImportDecl())
@@ -440,7 +464,8 @@ public struct ImportTS {
440464
name: Self.thunkName(function: function),
441465
parameters: function.parameters,
442466
returnType: function.returnType,
443-
effects: function.effects
467+
effects: function.effects,
468+
genericParameters: function.genericParameters ?? []
444469
)
445470
.with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation))
446471
]
@@ -959,6 +984,8 @@ extension BridgeType {
959984
return LoweringParameterInfo(loweredParameters: [])
960985
case .alias:
961986
preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching loweringParameterInfo")
987+
case .generic:
988+
return LoweringParameterInfo(loweredParameters: [])
962989
}
963990
}
964991

@@ -1033,6 +1060,8 @@ extension BridgeType {
10331060
return LiftingReturnInfo(valueToLift: nil)
10341061
case .alias:
10351062
preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching liftingReturnInfo")
1063+
case .generic:
1064+
return LiftingReturnInfo(valueToLift: nil)
10361065
}
10371066
}
10381067
}

0 commit comments

Comments
 (0)