Skip to content

Commit 1e276d5

Browse files
committed
BridgeJS: Optional enums with associated value support
BridgeJS: Optional case enum, optional raw enum support BridgeJS: Simplify JS glue code as much as possible + basic docs
1 parent 55ee129 commit 1e276d5

32 files changed

+2113
-566
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -735,15 +735,14 @@ public class ExportSwift {
735735
}
736736

737737
func lookupType(for type: TypeSyntax) -> BridgeType? {
738-
// 1. Handle T? syntax (OptionalTypeSyntax)
738+
// T?
739739
if let optionalType = type.as(OptionalTypeSyntax.self) {
740740
let wrappedType = optionalType.wrappedType
741741
if let baseType = lookupType(for: wrappedType) {
742742
return .optional(baseType)
743743
}
744744
}
745-
746-
// 2. Handle Optional<T> syntax (IdentifierTypeSyntax with generic arguments)
745+
// Optional<T>
747746
if let identifierType = type.as(IdentifierTypeSyntax.self),
748747
identifierType.name.text == "Optional",
749748
let genericArgs = identifierType.genericArgumentClause?.arguments,
@@ -753,8 +752,7 @@ public class ExportSwift {
753752
return .optional(baseType)
754753
}
755754
}
756-
757-
// 3. Handle Swift.Optional<T> syntax (MemberTypeSyntax)
755+
// Swift.Optional<T>
758756
if let memberType = type.as(MemberTypeSyntax.self),
759757
let baseType = memberType.baseType.as(IdentifierTypeSyntax.self),
760758
baseType.name.text == "Swift",
@@ -766,22 +764,17 @@ public class ExportSwift {
766764
return .optional(wrappedType)
767765
}
768766
}
769-
770-
// 4. Handle type aliases - try to resolve through type declaration resolver first
771767
if let aliasDecl = typeDeclResolver.resolveTypeAlias(type) {
772-
// Recursively lookup the aliased type
773768
if let resolvedType = lookupType(for: aliasDecl.initializer.value) {
774769
return resolvedType
775770
}
776771
}
777772

778-
// 5. Handle primitive types before falling back to other type declarations
779773
let typeName = type.trimmedDescription
780774
if let primitiveType = BridgeType.primitive(swiftType: typeName) {
781775
return primitiveType
782776
}
783777

784-
// 6. Try to resolve other type declarations
785778
guard let typeDecl = typeDeclResolver.resolve(type) else {
786779
return nil
787780
}
@@ -898,7 +891,6 @@ public class ExportSwift {
898891
argumentsToLift = liftingInfo.parameters.map { (name, _) in param.name + name.capitalizedFirstLetter }
899892
}
900893

901-
// For optional types, use Optional<WrappedType> syntax instead of WrappedType?
902894
let typeNameForIntrinsic: String
903895
switch param.type {
904896
case .optional(let wrappedType):
@@ -1004,7 +996,6 @@ public class ExportSwift {
1004996
return
1005997
}
1006998

1007-
// Handle optional types that use special storage functions and return Void
1008999
if case .optional(_) = returnType {
10091000
append("return ret.bridgeJSLowerReturn()")
10101001
return
@@ -1095,7 +1086,7 @@ public class ExportSwift {
10951086
let valueSwitch = (["switch self {"] + valueCases + ["}"]).joined(separator: "\n")
10961087

10971088
return """
1098-
extension \(raw: typeName) {
1089+
extension \(raw: typeName): _BridgedSwiftCaseEnum {
10991090
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
11001091
return bridgeJSRawValue
11011092
}
@@ -1123,15 +1114,15 @@ public class ExportSwift {
11231114
func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax {
11241115
let typeName = enumDef.swiftCallName
11251116
return """
1126-
private extension \(raw: typeName) {
1127-
static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) {
1117+
extension \(raw: typeName): _BridgedSwiftAssociatedValueEnum {
1118+
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) {
11281119
switch caseId {
11291120
\(raw: generateStackLiftSwitchCases(enumDef: enumDef).joined(separator: "\n"))
11301121
default: fatalError("Unknown \(raw: typeName) case ID: \\(caseId)")
11311122
}
11321123
}
11331124
1134-
func bridgeJSLowerReturn() {
1125+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() {
11351126
switch self {
11361127
\(raw: generateReturnSwitchCases(enumDef: enumDef).joined(separator: "\n"))
11371128
}
@@ -1168,7 +1159,7 @@ public class ExportSwift {
11681159
case .double:
11691160
return "\(paramName)Double.bridgeJSLiftParameter(_swift_js_pop_param_f64())"
11701161
case .optional(_):
1171-
return "/* Optional associated value lifting not yet implemented */nil" // Placeholder
1162+
return "nil"
11721163
default:
11731164
return "\(paramName)Int.bridgeJSLiftParameter(_swift_js_pop_param_int32())"
11741165
}
@@ -1205,8 +1196,6 @@ public class ExportSwift {
12051196
bodyLines.append("_swift_js_push_f32(\(paramName))")
12061197
case .double:
12071198
bodyLines.append("_swift_js_push_f64(\(paramName))")
1208-
case .optional(_):
1209-
bodyLines.append("// Optional associated value lowering not yet implemented") // Placeholder
12101199
default:
12111200
bodyLines.append(
12121201
"preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")"
@@ -1494,7 +1483,7 @@ extension BridgeType {
14941483
case .jsObject(let name?): return name
14951484
case .swiftHeapObject(let name): return name
14961485
case .void: return "Void"
1497-
case .optional(let wrappedType): return "\(wrappedType.swiftType)?"
1486+
case .optional(let wrappedType): return "Optional<\(wrappedType.swiftType)>"
14981487
case .caseEnum(let name): return name
14991488
case .rawValueEnum(let name, _): return name
15001489
case .associatedValueEnum(let name): return name
@@ -1531,7 +1520,6 @@ extension BridgeType {
15311520
case .swiftHeapObject: return .swiftHeapObject
15321521
case .void: return .void
15331522
case .optional(let wrappedType):
1534-
// Optional parameters include optionality flag plus wrapped type parameters
15351523
var optionalParams: [(name: String, type: WasmCoreType)] = [("isSome", .i32)]
15361524
optionalParams.append(contentsOf: try wrappedType.liftParameterInfo().parameters)
15371525
return LiftingIntrinsicInfo(parameters: optionalParams)
@@ -1570,6 +1558,7 @@ extension BridgeType {
15701558
static let caseEnum = LoweringIntrinsicInfo(returnType: .i32)
15711559
static let rawValueEnum = LoweringIntrinsicInfo(returnType: .i32)
15721560
static let associatedValueEnum = LoweringIntrinsicInfo(returnType: nil)
1561+
static let optional = LoweringIntrinsicInfo(returnType: nil)
15731562
}
15741563

15751564
func loweringReturnInfo() throws -> LoweringIntrinsicInfo {
@@ -1582,9 +1571,7 @@ extension BridgeType {
15821571
case .jsObject: return .jsObject
15831572
case .swiftHeapObject: return .swiftHeapObject
15841573
case .void: return .void
1585-
case .optional(_):
1586-
// Optional return values use special storage functions and return void
1587-
return LoweringIntrinsicInfo(returnType: nil)
1574+
case .optional: return .optional
15881575
case .caseEnum: return .caseEnum
15891576
case .rawValueEnum(_, let rawType):
15901577
switch rawType {
@@ -1602,7 +1589,7 @@ extension BridgeType {
16021589
case .associatedValueEnum:
16031590
return .associatedValueEnum
16041591
case .namespaceEnum:
1605-
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
1592+
throw BridgeJSCoreError("Namespace enums are not supported as return types")
16061593
}
16071594
}
16081595
}

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,51 +72,18 @@ public struct ImportTS {
7272

7373
func lowerParameter(param: Parameter) throws {
7474
let loweringInfo = try param.type.loweringParameterInfo()
75-
76-
// Handle void parameters (empty loweredParameters array)
77-
if loweringInfo.loweredParameters.isEmpty {
78-
// Void parameters don't generate any ABI parameters
79-
return
80-
} else if loweringInfo.loweredParameters.count == 1 {
81-
// Simple case: single parameter
82-
let (_, type) = loweringInfo.loweredParameters[0]
83-
abiParameterForwardings.append(
84-
LabeledExprSyntax(
85-
label: param.label,
86-
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
87-
)
88-
)
89-
abiParameterSignatures.append((param.name, type))
90-
} else {
91-
// Complex case: multiple parameters (e.g., optionals with isSome flag + wrapped parameters)
92-
// For optional types, use Optional<WrappedType> syntax for the lowering call
93-
let typeNameForLowering: String
94-
switch param.type {
95-
case .optional(let wrappedType):
96-
typeNameForLowering = "Optional<\(wrappedType.swiftType)>"
97-
default:
98-
typeNameForLowering = param.type.swiftType
99-
}
100-
101-
let paramNames = loweringInfo.loweredParameters.enumerated().map { index, paramInfo in
102-
if index == 0 {
103-
return param.name + paramInfo.name.capitalizedFirstLetter
104-
} else {
105-
return param.name + paramInfo.name.capitalizedFirstLetter
106-
}
107-
}
108-
109-
abiParameterForwardings.append(
110-
LabeledExprSyntax(
111-
label: param.label,
112-
expression: ExprSyntax("\(raw: typeNameForLowering).bridgeJSLowerParameter(\(raw: param.name))")
113-
)
75+
assert(
76+
loweringInfo.loweredParameters.count == 1,
77+
"For now, we require a single parameter to be lowered to a single Wasm core type"
78+
)
79+
let (_, type) = loweringInfo.loweredParameters[0]
80+
abiParameterForwardings.append(
81+
LabeledExprSyntax(
82+
label: param.label,
83+
expression: ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
11484
)
115-
116-
for (paramName, (_, type)) in zip(paramNames, loweringInfo.loweredParameters) {
117-
abiParameterSignatures.append((paramName, type))
118-
}
119-
}
85+
)
86+
abiParameterSignatures.append((param.name, type))
12087
}
12188

12289
func call(returnType: BridgeType) {
@@ -136,13 +103,6 @@ public struct ImportTS {
136103
if returnType == .void {
137104
return
138105
}
139-
140-
// Handle optional return values that use special storage functions
141-
if case .optional(_) = returnType {
142-
body.append("return \(raw: returnType.swiftType).bridgeJSLiftReturn()")
143-
return
144-
}
145-
146106
body.append("return \(raw: returnType.swiftType).bridgeJSLiftReturn(ret)")
147107
}
148108

@@ -473,16 +433,12 @@ extension BridgeType {
473433
case .string: return .string
474434
case .jsObject: return .jsObject
475435
case .void: return .void
476-
case .optional(let wrappedType):
477-
// Optional parameters include optionality flag plus wrapped type parameters
478-
let wrappedInfo = try wrappedType.loweringParameterInfo()
479-
var optionalParams: [(name: String, type: WasmCoreType)] = [("isSome", .i32)]
480-
optionalParams.append(contentsOf: wrappedInfo.loweredParameters)
481-
return LoweringParameterInfo(loweredParameters: optionalParams)
482436
case .swiftHeapObject:
483437
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
484438
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
485439
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
440+
case .optional:
441+
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
486442
}
487443
}
488444

@@ -507,13 +463,12 @@ extension BridgeType {
507463
case .string: return .string
508464
case .jsObject: return .jsObject
509465
case .void: return .void
510-
case .optional(_):
511-
// Optional return values use special storage functions and return void
512-
return LiftingReturnInfo(valueToLift: nil)
513466
case .swiftHeapObject:
514467
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
515468
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
516469
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
470+
case .optional:
471+
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
517472
}
518473
}
519474
}

0 commit comments

Comments
 (0)