Skip to content

Commit b3d6dcf

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

12 files changed

Lines changed: 573 additions & 28 deletions

File tree

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

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

27-
public init(progress: ProgressReporting, moduleName: String, skeleton: ExportedSkeleton) {
28+
private var hasGenerics: Bool {
29+
let hasGenericExports = skeleton.functions.contains { !($0.genericParameterNames.isEmpty) }
30+
let hasGenericImports =
31+
imported?.children.contains { file in
32+
file.functions.contains { !($0.genericParameterNames.isEmpty) }
33+
} ?? false
34+
return hasGenericExports || hasGenericImports
35+
}
36+
37+
public init(
38+
progress: ProgressReporting,
39+
moduleName: String,
40+
skeleton: ExportedSkeleton,
41+
imported: ImportedModuleSkeleton? = nil
42+
) {
2843
self.progress = progress
2944
self.moduleName = moduleName
3045
self.exposeToGlobal = skeleton.exposeToGlobal
3146
self.skeleton = skeleton
47+
self.imported = imported
3248
}
3349

3450
/// Finalizes the export process and generates the bridge code
@@ -80,6 +96,9 @@ public class ExportSwift {
8096
let structCodegen = StructCodegen()
8197
for structDef in skeleton.structs {
8298
decls.append(contentsOf: structCodegen.renderStructHelpers(structDef))
99+
if hasGenerics {
100+
decls.append(contentsOf: renderStructGenericConformance(structDef: structDef))
101+
}
83102
decls.append(contentsOf: try renderSingleExportedStruct(struct: structDef))
84103
}
85104

@@ -817,9 +836,45 @@ public class ExportSwift {
817836
// Generate ConvertibleToJSValue extension
818837
decls.append(contentsOf: renderConvertibleToJSValueExtension(klass: klass))
819838

839+
if hasGenerics, klass.isFinal == true {
840+
decls.append(contentsOf: renderClassGenericConformance(klass: klass))
841+
}
842+
820843
return decls
821844
}
822845

846+
private func renderClassGenericConformance(klass: ExportedClass) -> [DeclSyntax] {
847+
let typeName = klass.swiftCallName
848+
let printer = CodeFragmentPrinter()
849+
printer.write("extension \(typeName): _BridgedSwiftGenericBridgeable {")
850+
printer.indent {
851+
printer.write(
852+
"@_spi(BridgeJS) public static var bridgeJSTypeName: StaticString { \"\(klass.abiName)\" }"
853+
)
854+
printer.write(
855+
"@_spi(BridgeJS) public static let bridgeJSTypeID: Int32 = _swift_js_resolve_type_id(\(typeName).bridgeJSTypeName)"
856+
)
857+
}
858+
printer.write("}")
859+
return ["\(raw: printer.lines.joined(separator: "\n"))"]
860+
}
861+
862+
private func renderStructGenericConformance(structDef: ExportedStruct) -> [DeclSyntax] {
863+
let typeName = structDef.swiftCallName
864+
let printer = CodeFragmentPrinter()
865+
printer.write("extension \(typeName): _BridgedSwiftGenericBridgeable {")
866+
printer.indent {
867+
printer.write(
868+
"@_spi(BridgeJS) public static var bridgeJSTypeName: StaticString { \"\(structDef.abiName)\" }"
869+
)
870+
printer.write(
871+
"@_spi(BridgeJS) public static let bridgeJSTypeID: Int32 = _swift_js_resolve_type_id(\(typeName).bridgeJSTypeName)"
872+
)
873+
}
874+
printer.write("}")
875+
return ["\(raw: printer.lines.joined(separator: "\n"))"]
876+
}
877+
823878
/// Generates a ConvertibleToJSValue extension for the exported class
824879
///
825880
/// # Example
@@ -887,6 +942,8 @@ struct StackCodegen {
887942
return "JSObject.bridgeJSStackPop()"
888943
case .void, .namespaceEnum:
889944
return "()"
945+
case .generic:
946+
fatalError("Generic type parameters are not supported in exported declarations")
890947
}
891948
}
892949

@@ -899,7 +956,7 @@ struct StackCodegen {
899956
return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()"
900957
case .jsObject(let className?):
901958
return "\(raw: typeName)<JSObject>.bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }"
902-
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol:
959+
case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol, .generic:
903960
fatalError("Invalid nullable wrapped type: \(wrappedType)")
904961
}
905962
}
@@ -932,6 +989,8 @@ struct StackCodegen {
932989
return lowerArrayStatements(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
933990
case .dictionary(let valueType):
934991
return lowerDictionaryStatements(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
992+
case .generic:
993+
fatalError("Generic type parameters are not supported in exported declarations")
935994
}
936995
}
937996

@@ -1312,10 +1371,12 @@ struct StructCodegen {
13121371
returnType: .i32
13131372
)
13141373

1315-
return [
1374+
var decls: [DeclSyntax] = [
13161375
bridgedStructExtension, "\(raw: lowerExternDeclPrinter.lines.joined(separator: "\n"))",
13171376
"\(raw: liftExternDeclPrinter.lines.joined(separator: "\n"))",
13181377
]
1378+
1379+
return decls
13191380
}
13201381

13211382
private func generateStructLiftCode(structDef: ExportedStruct) -> [String] {
@@ -1593,6 +1654,7 @@ extension BridgeType {
15931654
let effectsStr = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "")
15941655
let closureType = "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)"
15951656
return useJSTypedClosure ? "JSTypedClosure<\(closureType)>" : closureType
1657+
case .generic(let name): return name
15961658
}
15971659
}
15981660

@@ -1675,6 +1737,8 @@ extension BridgeType {
16751737
return LiftingIntrinsicInfo(parameters: [("callbackId", .i32)])
16761738
case .array, .dictionary:
16771739
return LiftingIntrinsicInfo(parameters: [])
1740+
case .generic:
1741+
throw BridgeJSCoreError("Generic type parameters are not supported in exported declarations")
16781742
}
16791743
}
16801744

@@ -1726,6 +1790,8 @@ extension BridgeType {
17261790
return .jsObject
17271791
case .array, .dictionary:
17281792
return .array
1793+
case .generic:
1794+
throw BridgeJSCoreError("Generic type parameters are not supported in exported declarations")
17291795
}
17301796
}
17311797
}

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)