Skip to content

Commit 56cbb3b

Browse files
committed
BridgeJS: Support generic exports, callbacks, and initializers
1 parent 53e8cc1 commit 56cbb3b

8 files changed

Lines changed: 1449 additions & 224 deletions

File tree

‎Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift‎

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public struct ClosureCodegen {
4747
for (index, paramType) in signature.parameters.enumerated() {
4848
try builder.lowerParameter(param: Parameter(label: nil, name: "param\(index)", type: paramType))
4949
}
50+
builder.appendTypeIDParameters(signature.genericParameterNames)
5051

5152
// Generate the call and return value lifting
5253
try builder.call()
@@ -69,7 +70,14 @@ public struct ClosureCodegen {
6970
let helperEnumDeclPrinter = CodeFragmentPrinter()
7071
helperEnumDeclPrinter.write("private enum \(helperName) {")
7172
helperEnumDeclPrinter.indent {
72-
helperEnumDeclPrinter.write("static func bridgeJSLift(_ callbackId: Int32) -> \(swiftClosureType) {")
73+
let genericNames = signature.genericParameterNames
74+
let genericClause =
75+
genericNames.isEmpty
76+
? "" : "<\(genericNames.map { "\($0): BridgedSwiftGenericBridgeable" }.joined(separator: ", "))>"
77+
let parameters = (["_ callbackId: Int32"] + genericNames.map { "_: \($0).Type" }).joined(separator: ", ")
78+
helperEnumDeclPrinter.write(
79+
"static func bridgeJSLift\(genericClause)(\(parameters)) -> \(swiftClosureType) {"
80+
)
7381
helperEnumDeclPrinter.indent {
7482
helperEnumDeclPrinter.write("let callback = JSObject.bridgeJSLiftParameter(callbackId)")
7583
let parameters: String
@@ -112,6 +120,10 @@ public struct ClosureCodegen {
112120

113121
let helperEnumDecl: DeclSyntax = "\(raw: helperEnumDeclPrinter.lines.joined(separator: "\n"))"
114122

123+
if !signature.genericParameterNames.isEmpty {
124+
return [externDecl, helperEnumDecl]
125+
}
126+
115127
let accessModifier = accessLevel.modifierKeyword.map { "\($0) " } ?? ""
116128
let declaration = signature.sendingParameters ? "static func sending" : "init"
117129
let returnClause = signature.sendingParameters ? " -> Self" : ""
@@ -164,10 +176,38 @@ public struct ClosureCodegen {
164176
guard !signatureAccessLevels.isEmpty else { return nil }
165177

166178
var decls: [DeclSyntax] = []
179+
var asyncGenericResults = Set<BridgeType>()
167180
for signature in signatureAccessLevels.keys.sorted(by: { $0.mangleName < $1.mangleName }) {
168181
let accessLevel = signatureAccessLevels[signature] ?? .internal
169182
decls.append(contentsOf: try renderClosureHelpers(signature, accessLevel: accessLevel))
170-
decls.append(try renderClosureInvokeHandler(signature))
183+
if signature.genericParameterNames.isEmpty {
184+
decls.append(try renderClosureInvokeHandler(signature))
185+
}
186+
let returnType = signature.returnType
187+
if signature.isAsync, returnType.usesGenericParameter, asyncGenericResults.insert(returnType).inserted {
188+
let parameter = Parameter(label: nil, name: "value", type: .jsValue)
189+
let effects = Effects(isAsync: false, isThrows: true)
190+
let builder = try ImportTS.CallJSEmission(
191+
moduleName: "bjs",
192+
abiName: "async_callback_result_\(signature.moduleName)_\(returnType.mangleTypeName)",
193+
effects: effects,
194+
returnType: returnType
195+
)
196+
try builder.lowerParameter(param: parameter)
197+
builder.appendTypeIDParameters(returnType.referencedGenericNames)
198+
try builder.call()
199+
try builder.liftReturnValue()
200+
decls.append(builder.renderImportDecl())
201+
decls.append(
202+
builder.renderThunkDecl(
203+
name: "_bjs_async_result_\(returnType.mangleTypeName)",
204+
parameters: [parameter],
205+
returnType: returnType,
206+
effects: effects,
207+
genericParameters: returnType.referencedGenericNames.map { GenericParameter(name: $0) }
208+
)
209+
)
210+
}
171211
}
172212

173213
return withSpan("Format Closure Glue") {

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift‎

Lines changed: 240 additions & 20 deletions
Large diffs are not rendered by default.

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public struct ExternalModuleIndex {
77
public struct ExternalType: Equatable {
88
public let moduleName: String
99
public let bridgeType: BridgeType
10+
public var isGenericBridgeableProtocol = false
1011
}
1112

1213
public enum LookupResult: Equatable {
@@ -31,8 +32,12 @@ public struct ExternalModuleIndex {
3132
guard let exported = skeleton.exported else { continue }
3233
var moduleEntries = entriesByModule[moduleName] ?? [:]
3334

34-
func register(dotPath: String, bridgeType: BridgeType) {
35-
let externalType = ExternalType(moduleName: moduleName, bridgeType: bridgeType)
35+
func register(dotPath: String, bridgeType: BridgeType, isGenericBridgeableProtocol: Bool = false) {
36+
let externalType = ExternalType(
37+
moduleName: moduleName,
38+
bridgeType: bridgeType,
39+
isGenericBridgeableProtocol: isGenericBridgeableProtocol
40+
)
3641
if moduleEntries[dotPath] == nil {
3742
moduleEntries[dotPath] = externalType
3843
entriesByDotPath[dotPath, default: []].append(externalType)
@@ -61,7 +66,11 @@ public struct ExternalModuleIndex {
6166
register(dotPath: enumDef.swiftCallName, bridgeType: bridgeType)
6267
}
6368
for proto in exported.protocols {
64-
register(dotPath: proto.name, bridgeType: .swiftProtocol(proto.name))
69+
register(
70+
dotPath: proto.name,
71+
bridgeType: .swiftProtocol(proto.name),
72+
isGenericBridgeableProtocol: proto.isGenericBridgeable == true
73+
)
6574
}
6675
for alias in exported.aliases {
6776
register(

‎Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public struct ImportTS {
346346
"\(tryKeyword) await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in"
347347
)
348348
} else {
349-
let resolveSwiftType = returnType.closureSwiftType
349+
let resolveSwiftType = returnType.usesGenericParameter ? "JSValue" : returnType.closureSwiftType
350350
let resolveFactory =
351351
"makeResolveClosure: { JSTypedClosure<(sending \(resolveSwiftType)) -> Void>.sending($0) }"
352352
body.write(
@@ -359,7 +359,11 @@ public struct ImportTS {
359359
body.write("}")
360360

361361
if returnType != .void {
362-
body.write("return resolved")
362+
if returnType.usesGenericParameter {
363+
body.write("return \(tryKeyword) _bjs_async_result_\(returnType.mangleTypeName)(resolved)")
364+
} else {
365+
body.write("return resolved")
366+
}
363367
}
364368
}
365369

@@ -381,7 +385,7 @@ public struct ImportTS {
381385
parameters: [Parameter],
382386
returnType: BridgeType,
383387
effects: Effects,
384-
genericParameters: [String] = []
388+
genericParameters: [GenericParameter] = []
385389
) -> DeclSyntax {
386390
let printer = CodeFragmentPrinter()
387391
let signature = SwiftSignatureBuilder.buildFunctionSignature(
@@ -393,7 +397,11 @@ public struct ImportTS {
393397
let genericClause =
394398
genericParameters.isEmpty
395399
? ""
396-
: "<" + genericParameters.map { "\($0): BridgedSwiftGenericBridgeable" }.joined(separator: ", ")
400+
: "<"
401+
+ genericParameters.map { genericParameter in
402+
let constraints = ["BridgedSwiftGenericBridgeable"] + genericParameter.constraints
403+
return "\(genericParameter.name): \(constraints.joined(separator: " & "))"
404+
}.joined(separator: ", ")
397405
+ ">"
398406
printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {")
399407
printer.indent {
@@ -465,7 +473,7 @@ public struct ImportTS {
465473
parameters: function.parameters,
466474
returnType: function.returnType,
467475
effects: function.effects,
468-
genericParameters: function.genericParameterNames
476+
genericParameters: function.genericParameters ?? []
469477
)
470478
.with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation))
471479
]
@@ -496,7 +504,7 @@ public struct ImportTS {
496504
parameters: [selfParameter] + method.parameters,
497505
returnType: method.returnType,
498506
effects: method.effects,
499-
genericParameters: method.genericParameterNames
507+
genericParameters: method.genericParameters ?? []
500508
)
501509
]
502510
}
@@ -522,7 +530,7 @@ public struct ImportTS {
522530
parameters: method.parameters,
523531
returnType: method.returnType,
524532
effects: method.effects,
525-
genericParameters: method.genericParameterNames
533+
genericParameters: method.genericParameters ?? []
526534
)
527535
]
528536
}
@@ -548,7 +556,7 @@ public struct ImportTS {
548556
parameters: constructor.parameters,
549557
returnType: .jsObject(nil),
550558
effects: effects,
551-
genericParameters: constructor.genericParameterNames
559+
genericParameters: constructor.genericParameters ?? []
552560
)
553561
]
554562
}

0 commit comments

Comments
 (0)