Skip to content

Commit e8fd782

Browse files
committed
BridgeJS: Add OptionalConvention, move side-channel/stack flags to descriptor, unify return-type switches
1 parent 3bd1aca commit e8fd782

File tree

23 files changed

+1537
-1640
lines changed

23 files changed

+1537
-1640
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,12 @@ public struct ClosureCodegen {
148148
let abiReturnWasmType: WasmCoreType?
149149
if signature.returnType == .void {
150150
abiReturnWasmType = nil
151-
} else if let wasmType = try signature.returnType.loweringReturnInfo().returnType {
151+
} else if let wasmType = try signature.returnType.loweringReturnInfo() {
152152
abiReturnWasmType = wasmType
153153
} else {
154154
abiReturnWasmType = nil
155155
}
156156

157-
let throwReturn = abiReturnWasmType?.swiftReturnPlaceholderStmt ?? "return"
158-
159157
// Build signature using SwiftSignatureBuilder
160158
let funcSignature = SwiftSignatureBuilder.buildABIFunctionSignature(
161159
abiParameters: abiParams,

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 49 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -134,39 +134,26 @@ public class ExportSwift {
134134
case .closure(let signature, _):
135135
typeNameForIntrinsic = param.type.swiftType
136136
liftingExpr = ExprSyntax("_BJS_Closure_\(raw: signature.mangleName).bridgeJSLift(\(raw: param.name))")
137-
case .swiftStruct(let structName):
138-
typeNameForIntrinsic = structName
139-
liftingExpr = ExprSyntax("\(raw: structName).bridgeJSLiftParameter()")
140137
case .array:
141138
typeNameForIntrinsic = param.type.swiftType
142139
liftingExpr = StackCodegen().liftExpression(for: param.type)
143140
case .nullable(let wrappedType, let kind):
144-
let optionalSwiftType: String
145-
if case .null = kind {
146-
optionalSwiftType = "Optional"
147-
} else {
148-
optionalSwiftType = "JSUndefinedOr"
149-
}
150-
if case .swiftProtocol(let protocolName) = wrappedType {
151-
let wrapperName = "Any\(protocolName)"
152-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrapperName)>"
153-
liftingExpr = ExprSyntax(
154-
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
155-
)
156-
} else {
157-
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>"
158-
liftingExpr = ExprSyntax(
159-
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
160-
)
161-
}
162-
case .swiftProtocol(let protocolName):
163-
let wrapperName = "Any\(protocolName)"
164-
typeNameForIntrinsic = wrapperName
141+
let optionalSwiftType: String =
142+
if case .null = kind { "Optional" } else { "JSUndefinedOr" }
143+
let wrappedName: String =
144+
if case .cast(let name) = wrappedType.descriptor.accessorTransform { name } else {
145+
wrappedType.swiftType
146+
}
147+
typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedName)>"
165148
liftingExpr = ExprSyntax(
166-
"\(raw: wrapperName).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
149+
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
167150
)
168151
default:
169-
typeNameForIntrinsic = param.type.swiftType
152+
if case .cast(let name) = param.type.descriptor.accessorTransform {
153+
typeNameForIntrinsic = name
154+
} else {
155+
typeNameForIntrinsic = param.type.swiftType
156+
}
170157
liftingExpr = ExprSyntax(
171158
"\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))"
172159
)
@@ -211,26 +198,9 @@ public class ExportSwift {
211198
if returnType == .void {
212199
return CodeBlockItemSyntax(item: .init(ExpressionStmtSyntax(expression: callExpr)))
213200
} else {
214-
switch returnType {
215-
case .swiftProtocol(let protocolName):
216-
let wrapperName = "Any\(protocolName)"
217-
return CodeBlockItemSyntax(
218-
item: .init(DeclSyntax("let ret = \(raw: callExpr) as! \(raw: wrapperName)"))
219-
)
220-
case .nullable(let wrappedType, _):
221-
if case .swiftProtocol(let protocolName) = wrappedType {
222-
let wrapperName = "Any\(protocolName)"
223-
return CodeBlockItemSyntax(
224-
item: .init(
225-
DeclSyntax("let ret = (\(raw: callExpr)).flatMap { $0 as? \(raw: wrapperName) }")
226-
)
227-
)
228-
} else {
229-
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
230-
}
231-
default:
232-
return CodeBlockItemSyntax(item: .init(DeclSyntax("let ret = \(raw: callExpr)")))
233-
}
201+
let binding = returnType.descriptor.accessorTransform
202+
.applyToReturnBinding("\(callExpr)", isOptional: returnType.isOptional)
203+
return CodeBlockItemSyntax(item: .init(DeclSyntax("\(raw: binding)")))
234204
}
235205
}
236206

@@ -244,20 +214,9 @@ public class ExportSwift {
244214
if returnType == .void {
245215
append("\(raw: name)")
246216
} else {
247-
switch returnType {
248-
case .swiftProtocol(let protocolName):
249-
let wrapperName = "Any\(protocolName)"
250-
append("let ret = \(raw: name) as! \(raw: wrapperName)")
251-
case .nullable(let wrappedType, _):
252-
if case .swiftProtocol(let protocolName) = wrappedType {
253-
let wrapperName = "Any\(protocolName)"
254-
append("let ret = \(raw: name).flatMap { $0 as? \(raw: wrapperName) }")
255-
} else {
256-
append("let ret = \(raw: name)")
257-
}
258-
default:
259-
append("let ret = \(raw: name)")
260-
}
217+
let binding = returnType.descriptor.accessorTransform
218+
.applyToReturnBinding(name, isOptional: returnType.isOptional)
219+
append("\(raw: binding)")
261220
}
262221
}
263222

@@ -274,14 +233,7 @@ public class ExportSwift {
274233
/// Generates intermediate variables for stack-using parameters if needed for LIFO compatibility
275234
private func generateParameterLifting() {
276235
let stackParamIndices = parameters.enumerated().compactMap { index, param -> Int? in
277-
switch param.type {
278-
case .swiftStruct, .nullable(.swiftStruct, _),
279-
.associatedValueEnum, .nullable(.associatedValueEnum, _),
280-
.array:
281-
return index
282-
default:
283-
return nil
284-
}
236+
param.type.descriptor.usesStackLifting ? index : nil
285237
}
286238

287239
guard stackParamIndices.count > 1 else { return }
@@ -298,23 +250,13 @@ public class ExportSwift {
298250

299251
func callPropertyGetter(propertyName: String, returnType: BridgeType) {
300252
let (_, selfExpr) = removeFirstLiftedParameter()
253+
let expr = "\(selfExpr).\(propertyName)"
301254
if returnType == .void {
302-
append("\(raw: selfExpr).\(raw: propertyName)")
255+
append("\(raw: expr)")
303256
} else {
304-
switch returnType {
305-
case .swiftProtocol(let protocolName):
306-
let wrapperName = "Any\(protocolName)"
307-
append("let ret = \(raw: selfExpr).\(raw: propertyName) as! \(raw: wrapperName)")
308-
case .nullable(let wrappedType, _):
309-
if case .swiftProtocol(let protocolName) = wrappedType {
310-
let wrapperName = "Any\(protocolName)"
311-
append("let ret = \(raw: selfExpr).\(raw: propertyName).flatMap { $0 as? \(raw: wrapperName) }")
312-
} else {
313-
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
314-
}
315-
default:
316-
append("let ret = \(raw: selfExpr).\(raw: propertyName)")
317-
}
257+
let binding = returnType.descriptor.accessorTransform
258+
.applyToReturnBinding(expr, isOptional: returnType.isOptional)
259+
append("\(raw: binding)")
318260
}
319261
}
320262

@@ -339,8 +281,7 @@ public class ExportSwift {
339281
}
340282

341283
private func _lowerReturnValue(returnType: BridgeType) throws {
342-
let loweringInfo = try returnType.loweringReturnInfo()
343-
abiReturnType = loweringInfo.returnType
284+
abiReturnType = try returnType.loweringReturnInfo()
344285
if returnType == .void {
345286
return
346287
}
@@ -784,6 +725,7 @@ struct StackCodegen {
784725
return "\(raw: type.swiftType).bridgeJSLiftParameter()"
785726
case .jsObject(let className?):
786727
return "\(raw: className)(unsafelyWrapping: JSObject.bridgeJSLiftParameter())"
728+
787729
case .nullable(let wrappedType, let kind):
788730
return liftNullableExpression(wrappedType: wrappedType, kind: kind)
789731
case .array(let elementType):
@@ -803,8 +745,6 @@ struct StackCodegen {
803745
return liftArrayExpressionInline(elementType: elementType)
804746
case .nullable, .closure:
805747
return liftArrayExpressionInline(elementType: elementType)
806-
case .void, .namespaceEnum:
807-
fatalError("Invalid array element type: \(elementType)")
808748
default:
809749
return "[\(raw: elementType.swiftType)].bridgeJSLiftParameter()"
810750
}
@@ -917,23 +857,16 @@ struct StackCodegen {
917857
accessor: String,
918858
varPrefix: String
919859
) -> [CodeBlockItemSyntax] {
920-
// Types needing accessor transformation
921-
switch elementType {
922-
case .jsObject(let className?) where className != "JSObject":
923-
return ["\(raw: accessor).map { $0.jsObject }.bridgeJSLowerReturn()"]
924-
case .swiftProtocol:
925-
return ["\(raw: accessor).map { $0 as! \(raw: elementType.swiftType) }.bridgeJSLowerReturn()"]
926-
case .nullable, .closure:
927-
return lowerArrayStatementsInline(
928-
elementType: elementType,
929-
accessor: accessor,
930-
varPrefix: varPrefix
931-
)
932-
case .void, .namespaceEnum:
933-
fatalError("Invalid array element type: \(elementType)")
934-
default:
935-
return ["\(raw: accessor).bridgeJSLowerReturn()"]
860+
if case .nullable = elementType {
861+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
862+
}
863+
if case .closure = elementType {
864+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
936865
}
866+
if let mapClosure = elementType.descriptor.accessorTransform.mapClosure {
867+
return ["\(raw: accessor).map { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
868+
}
869+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
937870
}
938871

939872
private func lowerArrayStatementsInline(
@@ -965,22 +898,16 @@ struct StackCodegen {
965898
accessor: String,
966899
varPrefix: String
967900
) -> [CodeBlockItemSyntax] {
968-
switch valueType {
969-
case .jsObject(let className?) where className != "JSObject":
970-
return ["\(raw: accessor).mapValues { $0.jsObject }.bridgeJSLowerReturn()"]
971-
case .swiftProtocol:
972-
return ["\(raw: accessor).mapValues { $0 as! \(raw: valueType.swiftType) }.bridgeJSLowerReturn()"]
973-
case .nullable, .closure:
974-
return lowerDictionaryStatementsInline(
975-
valueType: valueType,
976-
accessor: accessor,
977-
varPrefix: varPrefix
978-
)
979-
case .void, .namespaceEnum:
980-
fatalError("Invalid dictionary value type: \(valueType)")
981-
default:
982-
return ["\(raw: accessor).bridgeJSLowerReturn()"]
901+
if case .nullable = valueType {
902+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
903+
}
904+
if case .closure = valueType {
905+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
906+
}
907+
if let mapClosure = valueType.descriptor.accessorTransform.mapClosure {
908+
return ["\(raw: accessor).mapValues { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
983909
}
910+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
984911
}
985912

986913
private func lowerDictionaryStatementsInline(
@@ -1022,7 +949,7 @@ struct StackCodegen {
1022949
accessor: String,
1023950
varPrefix: String
1024951
) -> [CodeBlockItemSyntax] {
1025-
if wrappedType.descriptor.optionalUsesStackABI {
952+
if wrappedType.descriptor.optionalConvention == .stackABI {
1026953
return ["\(raw: accessor).bridgeJSLowerReturn()"]
1027954
}
1028955

@@ -1655,20 +1582,6 @@ extension BridgeType {
16551582
struct LiftingIntrinsicInfo: Sendable {
16561583
let parameters: [(name: String, type: WasmCoreType)]
16571584

1658-
static let bool = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1659-
static let int = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1660-
static let float = LiftingIntrinsicInfo(parameters: [("value", .f32)])
1661-
static let double = LiftingIntrinsicInfo(parameters: [("value", .f64)])
1662-
static let string = LiftingIntrinsicInfo(parameters: [("bytes", .i32), ("length", .i32)])
1663-
static let jsObject = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1664-
static let jsValue = LiftingIntrinsicInfo(parameters: [("kind", .i32), ("payload1", .i32), ("payload2", .f64)])
1665-
static let swiftHeapObject = LiftingIntrinsicInfo(parameters: [("value", .pointer)])
1666-
static let unsafePointer = LiftingIntrinsicInfo(parameters: [("pointer", .pointer)])
1667-
static let void = LiftingIntrinsicInfo(parameters: [])
1668-
static let caseEnum = LiftingIntrinsicInfo(parameters: [("value", .i32)])
1669-
static let associatedValueEnum = LiftingIntrinsicInfo(parameters: [
1670-
("caseId", .i32)
1671-
])
16721585
}
16731586

16741587
func liftParameterInfo() throws -> LiftingIntrinsicInfo {
@@ -1688,18 +1601,14 @@ extension BridgeType {
16881601
}
16891602
}
16901603

1691-
struct LoweringIntrinsicInfo: Sendable {
1692-
let returnType: WasmCoreType?
1693-
}
1694-
1695-
func loweringReturnInfo() throws -> LoweringIntrinsicInfo {
1604+
func loweringReturnInfo() throws -> WasmCoreType? {
16961605
switch self {
16971606
case .nullable:
1698-
return LoweringIntrinsicInfo(returnType: nil)
1607+
return nil
16991608
case .namespaceEnum:
17001609
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
17011610
default:
1702-
return LoweringIntrinsicInfo(returnType: descriptor.wasmReturnType)
1611+
return descriptor.wasmReturnType
17031612
}
17041613
}
17051614
}

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,15 +1535,15 @@ public struct BridgeJSLink {
15351535

15361536
switch enumDefinition.enumType {
15371537
case .simple:
1538-
let fragment = IntrinsicJSFragment.simpleEnumHelper(enumDefinition: enumDefinition)
1538+
let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition)
15391539
_ = try fragment.printCode([enumValuesName], context)
15401540
jsTopLevelLines.append(contentsOf: printer.lines)
15411541
case .rawValue:
15421542
guard enumDefinition.rawType != nil else {
15431543
throw BridgeJSLinkError(message: "Raw value enum \(enumDefinition.name) is missing rawType")
15441544
}
15451545

1546-
let fragment = IntrinsicJSFragment.rawValueEnumHelper(enumDefinition: enumDefinition)
1546+
let fragment = IntrinsicJSFragment.caseEnumHelper(enumDefinition: enumDefinition)
15471547
_ = try fragment.printCode([enumValuesName], context)
15481548
jsTopLevelLines.append(contentsOf: printer.lines)
15491549
case .associatedValue:
@@ -2172,7 +2172,7 @@ extension BridgeJSLink {
21722172
printer.write("} catch (error) {")
21732173
printer.indent {
21742174
printer.write("setException(error);")
2175-
if let abiReturnType = returnType.abiReturnType {
2175+
if !returnType.isOptional, let abiReturnType = returnType.descriptor.wasmReturnType {
21762176
printer.write("return \(abiReturnType.placeholderValue)")
21772177
}
21782178
}

0 commit comments

Comments
 (0)