Skip to content

Commit 0d96b11

Browse files
committed
BridgeJS: Generic function infrastructure and import implementation
1 parent fba3be0 commit 0d96b11

12 files changed

Lines changed: 617 additions & 30 deletions

File tree

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ public class ExportSwift {
2222
let moduleName: String
2323
private let exposeToGlobal: Bool
2424
private var skeleton: ExportedSkeleton
25+
private let hasGenerics: Bool
2526
private var sourceFiles: [(sourceFile: SourceFileSyntax, inputFilePath: String)] = []
2627

27-
public init(progress: ProgressReporting, moduleName: String, skeleton: ExportedSkeleton) {
28+
public init(
29+
progress: ProgressReporting,
30+
moduleName: String,
31+
skeleton: ExportedSkeleton,
32+
hasGenerics: Bool = false
33+
) {
2834
self.progress = progress
2935
self.moduleName = moduleName
3036
self.exposeToGlobal = skeleton.exposeToGlobal
3137
self.skeleton = skeleton
38+
self.hasGenerics = hasGenerics
3239
}
3340

3441
/// Finalizes the export process and generates the bridge code
@@ -77,7 +84,7 @@ public class ExportSwift {
7784
}
7885

7986
try withSpan("Render Structs") { [self] in
80-
let structCodegen = StructCodegen()
87+
let structCodegen = StructCodegen(hasGenerics: hasGenerics)
8188
for structDef in skeleton.structs {
8289
decls.append(contentsOf: structCodegen.renderStructHelpers(structDef))
8390
decls.append(contentsOf: try renderSingleExportedStruct(struct: structDef))
@@ -817,9 +824,29 @@ public class ExportSwift {
817824
// Generate ConvertibleToJSValue extension
818825
decls.append(contentsOf: renderConvertibleToJSValueExtension(klass: klass))
819826

827+
if hasGenerics, klass.isFinal == true {
828+
decls.append(contentsOf: renderClassGenericConformance(klass: klass))
829+
}
830+
820831
return decls
821832
}
822833

834+
private func renderClassGenericConformance(klass: ExportedClass) -> [DeclSyntax] {
835+
let typeName = klass.swiftCallName
836+
let printer = CodeFragmentPrinter()
837+
printer.write("extension \(typeName): _BridgedSwiftGenericBridgeable {")
838+
printer.indent {
839+
printer.write(
840+
"@_spi(BridgeJS) public static var bridgeJSTypeName: StaticString { \"\(klass.abiName)\" }"
841+
)
842+
printer.write(
843+
"@_spi(BridgeJS) public static let bridgeJSTypeID: Int32 = _swift_js_resolve_type_id(\(typeName).bridgeJSTypeName)"
844+
)
845+
}
846+
printer.write("}")
847+
return ["\(raw: printer.lines.joined(separator: "\n"))"]
848+
}
849+
823850
/// Generates a ConvertibleToJSValue extension for the exported class
824851
///
825852
/// # Example
@@ -887,6 +914,8 @@ struct StackCodegen {
887914
return "JSObject.bridgeJSStackPop()"
888915
case .void, .namespaceEnum:
889916
return "()"
917+
case .generic:
918+
fatalError("Generic type parameters are not supported in exported declarations")
890919
}
891920
}
892921

@@ -899,7 +928,7 @@ struct StackCodegen {
899928
return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()"
900929
case .jsObject(let className?):
901930
return "\(raw: typeName)<JSObject>.bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }"
902-
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol:
931+
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol, .generic:
903932
fatalError("Invalid nullable wrapped type: \(wrappedType)")
904933
}
905934
}
@@ -932,6 +961,8 @@ struct StackCodegen {
932961
return lowerArrayStatements(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
933962
case .dictionary(let valueType):
934963
return lowerDictionaryStatements(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
964+
case .generic:
965+
fatalError("Generic type parameters are not supported in exported declarations")
935966
}
936967
}
937968

@@ -1242,6 +1273,11 @@ struct EnumCodegen {
12421273

12431274
struct StructCodegen {
12441275
private let stackCodegen = StackCodegen()
1276+
private let hasGenerics: Bool
1277+
1278+
init(hasGenerics: Bool = false) {
1279+
self.hasGenerics = hasGenerics
1280+
}
12451281

12461282
func renderStructHelpers(_ structDef: ExportedStruct) -> [DeclSyntax] {
12471283
let typeName = structDef.swiftCallName
@@ -1312,10 +1348,27 @@ struct StructCodegen {
13121348
returnType: .i32
13131349
)
13141350

1315-
return [
1351+
var decls: [DeclSyntax] = [
13161352
bridgedStructExtension, "\(raw: lowerExternDeclPrinter.lines.joined(separator: "\n"))",
13171353
"\(raw: liftExternDeclPrinter.lines.joined(separator: "\n"))",
13181354
]
1355+
1356+
if hasGenerics {
1357+
let genericConformancePrinter = CodeFragmentPrinter()
1358+
genericConformancePrinter.write("extension \(typeName): _BridgedSwiftGenericBridgeable {")
1359+
genericConformancePrinter.indent {
1360+
genericConformancePrinter.write(
1361+
"@_spi(BridgeJS) public static var bridgeJSTypeName: StaticString { \"\(structDef.abiName)\" }"
1362+
)
1363+
genericConformancePrinter.write(
1364+
"@_spi(BridgeJS) public static let bridgeJSTypeID: Int32 = _swift_js_resolve_type_id(\(typeName).bridgeJSTypeName)"
1365+
)
1366+
}
1367+
genericConformancePrinter.write("}")
1368+
decls.append("\(raw: genericConformancePrinter.lines.joined(separator: "\n"))")
1369+
}
1370+
1371+
return decls
13191372
}
13201373

13211374
private func generateStructLiftCode(structDef: ExportedStruct) -> [String] {
@@ -1593,6 +1646,7 @@ extension BridgeType {
15931646
let effectsStr = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
15941647
let closureType = "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)"
15951648
return useJSTypedClosure ? "JSTypedClosure<\(closureType)>" : closureType
1649+
case .generic(let name): return name
15961650
}
15971651
}
15981652

@@ -1675,6 +1729,8 @@ extension BridgeType {
16751729
return LiftingIntrinsicInfo(parameters: [("callbackId", .i32)])
16761730
case .array, .dictionary:
16771731
return LiftingIntrinsicInfo(parameters: [])
1732+
case .generic:
1733+
throw BridgeJSCoreError("Generic type parameters are not supported in exported declarations")
16781734
}
16791735
}
16801736

@@ -1726,6 +1782,8 @@ extension BridgeType {
17261782
return .jsObject
17271783
case .array, .dictionary:
17281784
return .array
1785+
case .generic:
1786+
throw BridgeJSCoreError("Generic type parameters are not supported in exported declarations")
17291787
}
17301788
}
17311789
}

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 30 additions & 3 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 case .generic = param.type {
147+
stackLoweringStmts.insert("\(param.name).bridgeJSStackPush()", 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(genericParameterName: String) {
250+
let abiParamName = "\(genericParameterName.lowercased())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)
@@ -298,6 +309,8 @@ public struct ImportTS {
298309
} else {
299310
let liftExpr: String
300311
switch returnType {
312+
case .generic(let name):
313+
liftExpr = "\(name).bridgeJSStackPop()"
301314
case .closure(let signature, _):
302315
liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)"
303316
default:
@@ -363,7 +376,8 @@ public struct ImportTS {
363376
name: String,
364377
parameters: [Parameter],
365378
returnType: BridgeType,
366-
effects: Effects
379+
effects: Effects,
380+
genericParameters: [String] = []
367381
) -> DeclSyntax {
368382
let printer = CodeFragmentPrinter()
369383
let signature = SwiftSignatureBuilder.buildFunctionSignature(
@@ -372,7 +386,12 @@ public struct ImportTS {
372386
effects: effects,
373387
useWildcardLabels: true
374388
)
375-
printer.write("func \(name.backtickIfNeeded())\(signature) {")
389+
let genericClause =
390+
genericParameters.isEmpty
391+
? ""
392+
: "<" + genericParameters.map { "\($0): _BridgedSwiftGenericBridgeable" }.joined(separator: ", ")
393+
+ ">"
394+
printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {")
376395
printer.indent {
377396
printer.write(lines: body.lines)
378397
}
@@ -432,6 +451,9 @@ public struct ImportTS {
432451
for param in function.parameters {
433452
try builder.lowerParameter(param: param)
434453
}
454+
for genericParam in function.genericParameters {
455+
builder.appendTypeIDParameter(genericParameterName: genericParam)
456+
}
435457
try builder.call()
436458
try builder.liftReturnValue()
437459
topLevelDecls.append(builder.renderImportDecl())
@@ -440,7 +462,8 @@ public struct ImportTS {
440462
name: Self.thunkName(function: function),
441463
parameters: function.parameters,
442464
returnType: function.returnType,
443-
effects: function.effects
465+
effects: function.effects,
466+
genericParameters: function.genericParameters
444467
)
445468
.with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation))
446469
]
@@ -957,6 +980,8 @@ extension BridgeType {
957980
return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing)
958981
case .array, .dictionary:
959982
return LoweringParameterInfo(loweredParameters: [])
983+
case .generic:
984+
return LoweringParameterInfo(loweredParameters: [])
960985
}
961986
}
962987

@@ -1029,6 +1054,8 @@ extension BridgeType {
10291054
return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift)
10301055
case .array, .dictionary:
10311056
return LiftingReturnInfo(valueToLift: nil)
1057+
case .generic:
1058+
return LiftingReturnInfo(valueToLift: nil)
10321059
}
10331060
}
10341061
}

0 commit comments

Comments
 (0)