Skip to content

Commit d59368a

Browse files
committed
BridgeJS: Support for Optional<Type> for properties / method parameters / method return types in protocol
1 parent 731a047 commit d59368a

File tree

16 files changed

+708
-88
lines changed

16 files changed

+708
-88
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -982,16 +982,16 @@ public class ExportSwift {
982982
)
983983

984984
let protocolUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace)
985-
985+
986986
exportedProtocolByName[protocolUniqueKey] = ExportedProtocol(
987987
name: name,
988988
methods: [],
989989
properties: [],
990990
namespace: namespaceResult.namespace
991991
)
992-
992+
993993
stateStack.push(state: .protocolBody(name: name, key: protocolUniqueKey))
994-
994+
995995
var methods: [ExportedFunction] = []
996996
for member in node.memberBlock.members {
997997
if let funcDecl = member.decl.as(FunctionDeclSyntax.self) {
@@ -1013,10 +1013,10 @@ public class ExportSwift {
10131013
properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [],
10141014
namespace: namespaceResult.namespace
10151015
)
1016-
1016+
10171017
exportedProtocolByName[protocolUniqueKey] = exportedProtocol
10181018
exportedProtocolNames.append(protocolUniqueKey)
1019-
1019+
10201020
stateStack.pop()
10211021

10221022
parent.exportedProtocolNameByKey[protocolUniqueKey] = name
@@ -1097,14 +1097,6 @@ public class ExportSwift {
10971097
continue
10981098
}
10991099

1100-
if case .optional = propertyType {
1101-
diagnose(
1102-
node: typeAnnotation.type,
1103-
message: "Optional properties are not yet supported in protocols"
1104-
)
1105-
continue
1106-
}
1107-
11081100
guard let accessorBlock = binding.accessorBlock else {
11091101
diagnose(
11101102
node: binding,
@@ -1125,7 +1117,7 @@ public class ExportSwift {
11251117
if var currentProtocol = exportedProtocolByName[protocolKey] {
11261118
var properties = currentProtocol.properties
11271119
properties.append(exportedProperty)
1128-
1120+
11291121
currentProtocol = ExportedProtocol(
11301122
name: currentProtocol.name,
11311123
methods: currentProtocol.methods,
@@ -2240,15 +2232,34 @@ public class ExportSwift {
22402232
} else {
22412233
returnTypeStr = " -> \(method.returnType.swiftType)"
22422234
let liftingInfo = try method.returnType.liftingReturnInfo(context: .protocolExport)
2243-
if let abiType = liftingInfo.valueToLift {
2235+
2236+
if case .optional = method.returnType {
2237+
if let abiType = liftingInfo.valueToLift {
2238+
externReturnType = " -> \(abiType.swiftType)"
2239+
callCode = """
2240+
let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", ")))
2241+
return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret)
2242+
"""
2243+
} else {
2244+
externReturnType = ""
2245+
callCode = """
2246+
_extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", ")))
2247+
return \(raw: method.returnType.swiftType).bridgeJSLiftReturn()
2248+
"""
2249+
}
2250+
} else if let abiType = liftingInfo.valueToLift {
22442251
externReturnType = " -> \(abiType.swiftType)"
2252+
callCode = """
2253+
let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", ")))
2254+
return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret)
2255+
"""
22452256
} else {
22462257
externReturnType = ""
2258+
callCode = """
2259+
_extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", ")))
2260+
return \(raw: method.returnType.swiftType).bridgeJSLiftReturn()
2261+
"""
22472262
}
2248-
callCode = """
2249-
let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", ")))
2250-
return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret)
2251-
"""
22522263
}
22532264
let methodImplementation: DeclSyntax = """
22542265
func \(raw: method.name)(\(raw: swiftParams.joined(separator: ", ")))\(raw: returnTypeStr) {
@@ -2286,7 +2297,7 @@ public class ExportSwift {
22862297
}
22872298
"""
22882299
}
2289-
2300+
22902301
private func renderProtocolProperty(
22912302
property: ExportedProtocolProperty,
22922303
protocolName: String,
@@ -2306,27 +2317,27 @@ public class ExportSwift {
23062317
operation: "set",
23072318
className: protocolName
23082319
)
2309-
2320+
23102321
// Generate getter
23112322
let liftingInfo = try property.type.liftingReturnInfo(context: .protocolExport)
23122323
let getterReturnType: String
23132324
let getterCallCode: String
2314-
2325+
23152326
if let abiType = liftingInfo.valueToLift {
23162327
getterReturnType = " -> \(abiType.swiftType)"
23172328
getterCallCode = """
2318-
let ret = _extern_get(this: Int32(bitPattern: jsObject.id))
2319-
return \(property.type.swiftType).bridgeJSLiftReturn(ret)
2320-
"""
2329+
let ret = _extern_get(this: Int32(bitPattern: jsObject.id))
2330+
return \(property.type.swiftType).bridgeJSLiftReturn(ret)
2331+
"""
23212332
} else {
23222333
// For String and other types that use tmpRetString
23232334
getterReturnType = ""
23242335
getterCallCode = """
2325-
_extern_get(this: Int32(bitPattern: jsObject.id))
2326-
return \(property.type.swiftType).bridgeJSLiftReturn()
2327-
"""
2336+
_extern_get(this: Int32(bitPattern: jsObject.id))
2337+
return \(property.type.swiftType).bridgeJSLiftReturn()
2338+
"""
23282339
}
2329-
2340+
23302341
if property.isReadonly {
23312342
// Readonly property - only getter
23322343
return """
@@ -2345,11 +2356,11 @@ public class ExportSwift {
23452356
loweringInfo.loweredParameters.count == 1,
23462357
"Protocol property setters must lower to a single WASM parameter"
23472358
)
2348-
2359+
23492360
let (paramName, wasmType) = loweringInfo.loweredParameters[0]
23502361
let setterParams = "this: Int32, \(paramName): \(wasmType.swiftType)"
23512362
let setterCallArgs = "this: Int32(bitPattern: jsObject.id), \(paramName): newValue.bridgeJSLowerParameter()"
2352-
2363+
23532364
return """
23542365
var \(raw: property.name): \(raw: property.type.swiftType) {
23552366
get {
@@ -2542,6 +2553,7 @@ extension BridgeType {
25422553
throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters")
25432554
}
25442555
}
2556+
25452557
}
25462558

25472559
extension DeclModifierSyntax {

Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,13 @@ extension BridgeType {
449449
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
450450
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
451451
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
452-
case .optional:
453-
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
452+
case .optional(let wrappedType):
453+
switch context {
454+
case .importTS:
455+
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
456+
case .protocolExport:
457+
return try wrappedType.loweringParameterInfo(context: context)
458+
}
454459
}
455460
}
456461

@@ -492,7 +497,19 @@ extension BridgeType {
492497
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
493498
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
494499
case .optional:
495-
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
500+
switch context {
501+
case .importTS:
502+
throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports")
503+
case .protocolExport:
504+
// For Optional<String>, return the length (or -1 for null)
505+
if case .optional(.string) = self {
506+
return .string
507+
}
508+
if case .optional(.swiftHeapObject) = self {
509+
return LiftingReturnInfo(valueToLift: .pointer)
510+
}
511+
return LiftingReturnInfo(valueToLift: nil)
512+
}
496513
}
497514
}
498515
}

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,7 @@ extension BridgeJSLink {
18831883
valuesToLift = [scope.variable(param.name)]
18841884
} else {
18851885
valuesToLift = liftingFragment.parameters.map { scope.variable(param.name + $0.capitalizedFirstLetter) }
1886+
parameterNames.append(contentsOf: valuesToLift)
18861887
}
18871888
let liftedValues = liftingFragment.printCode(valuesToLift, scope, body, cleanupCode)
18881889
assert(liftedValues.count == 1, "Lifting fragment should produce exactly one value")
@@ -2455,7 +2456,7 @@ extension BridgeJSLink {
24552456
returnType: property.type
24562457
)
24572458
importObjectBuilder.assignToImportObject(name: getterAbiName, function: getterLines)
2458-
2459+
24592460
if !property.isReadonly {
24602461
let setterAbiName = ABINameGenerator.generateABIName(
24612462
baseName: property.name,

0 commit comments

Comments
 (0)