Skip to content

Commit 7ea4e16

Browse files
committed
BridgeJS: Move usesSideChannelForOptionalReturn and usesStackLifting into descriptor, unify return-type switches
BridgeJS: Code review polish — descriptor-driven liftExpression/emitOptionalPlaceholders, trailing comma fix, throw on unknown types BridgeJS: Use descriptor-driven handling in JSGlueGen to eliminate per-type switches BridgeJS: Delete dead code and fix nullable descriptor transparency in catch blocks
1 parent 271855a commit 7ea4e16

File tree

15 files changed

+702
-1091
lines changed

15 files changed

+702
-1091
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: 47 additions & 139 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
}
@@ -803,8 +744,6 @@ struct StackCodegen {
803744
return liftArrayExpressionInline(elementType: elementType)
804745
case .nullable, .closure:
805746
return liftArrayExpressionInline(elementType: elementType)
806-
case .void, .namespaceEnum:
807-
fatalError("Invalid array element type: \(elementType)")
808747
default:
809748
return "[\(raw: elementType.swiftType)].bridgeJSLiftParameter()"
810749
}
@@ -917,23 +856,16 @@ struct StackCodegen {
917856
accessor: String,
918857
varPrefix: String
919858
) -> [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()"]
859+
if case .nullable = elementType {
860+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
861+
}
862+
if case .closure = elementType {
863+
return lowerArrayStatementsInline(elementType: elementType, accessor: accessor, varPrefix: varPrefix)
936864
}
865+
if let mapClosure = elementType.descriptor.accessorTransform.mapClosure {
866+
return ["\(raw: accessor).map { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
867+
}
868+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
937869
}
938870

939871
private func lowerArrayStatementsInline(
@@ -965,22 +897,16 @@ struct StackCodegen {
965897
accessor: String,
966898
varPrefix: String
967899
) -> [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()"]
900+
if case .nullable = valueType {
901+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
902+
}
903+
if case .closure = valueType {
904+
return lowerDictionaryStatementsInline(valueType: valueType, accessor: accessor, varPrefix: varPrefix)
905+
}
906+
if let mapClosure = valueType.descriptor.accessorTransform.mapClosure {
907+
return ["\(raw: accessor).mapValues { \(raw: mapClosure) }.bridgeJSLowerReturn()"]
983908
}
909+
return ["\(raw: accessor).bridgeJSLowerReturn()"]
984910
}
985911

986912
private func lowerDictionaryStatementsInline(
@@ -1655,20 +1581,6 @@ extension BridgeType {
16551581
struct LiftingIntrinsicInfo: Sendable {
16561582
let parameters: [(name: String, type: WasmCoreType)]
16571583

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-
])
16721584
}
16731585

16741586
func liftParameterInfo() throws -> LiftingIntrinsicInfo {
@@ -1688,18 +1600,14 @@ extension BridgeType {
16881600
}
16891601
}
16901602

1691-
struct LoweringIntrinsicInfo: Sendable {
1692-
let returnType: WasmCoreType?
1693-
}
1694-
1695-
func loweringReturnInfo() throws -> LoweringIntrinsicInfo {
1603+
func loweringReturnInfo() throws -> WasmCoreType? {
16961604
switch self {
16971605
case .nullable:
1698-
return LoweringIntrinsicInfo(returnType: nil)
1606+
return nil
16991607
case .namespaceEnum:
17001608
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
17011609
default:
1702-
return LoweringIntrinsicInfo(returnType: descriptor.wasmReturnType)
1610+
return descriptor.wasmReturnType
17031611
}
17041612
}
17051613
}

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)