@@ -143,6 +143,14 @@ public class ExportSwift {
143
143
)
144
144
}
145
145
146
+ private func diagnoseNestedOptional( node: some SyntaxProtocol , type: String ) {
147
+ diagnose (
148
+ node: node,
149
+ message: " Nested optional types are not supported: \( type) " ,
150
+ hint: " Use a single optional like String? instead of String?? or Optional<Optional<T>> "
151
+ )
152
+ }
153
+
146
154
override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
147
155
switch state {
148
156
case . topLevel:
@@ -183,17 +191,32 @@ public class ExportSwift {
183
191
184
192
var parameters : [ Parameter ] = [ ]
185
193
for param in node. signature. parameterClause. parameters {
186
- guard let type = self . parent. lookupType ( for: param. type) else {
194
+ let resolvedType = self . parent. lookupType ( for: param. type)
195
+
196
+ if let type = resolvedType, case . optional( let wrappedType) = type, wrappedType. isOptional {
197
+ diagnoseNestedOptional ( node: param. type, type: param. type. trimmedDescription)
198
+ continue
199
+ }
200
+
201
+ guard let type = resolvedType else {
187
202
diagnoseUnsupportedType ( node: param. type, type: param. type. trimmedDescription)
188
203
continue
189
204
}
205
+
190
206
let name = param. secondName? . text ?? param. firstName. text
191
207
let label = param. firstName. text
192
208
parameters. append ( Parameter ( label: label, name: name, type: type) )
193
209
}
194
210
let returnType : BridgeType
195
211
if let returnClause = node. signature. returnClause {
196
- guard let type = self . parent. lookupType ( for: returnClause. type) else {
212
+ let resolvedType = self . parent. lookupType ( for: returnClause. type)
213
+
214
+ if let type = resolvedType, case . optional( let wrappedType) = type, wrappedType. isOptional {
215
+ diagnoseNestedOptional ( node: returnClause. type, type: returnClause. type. trimmedDescription)
216
+ return nil
217
+ }
218
+
219
+ guard let type = resolvedType else {
197
220
diagnoseUnsupportedType ( node: returnClause. type, type: returnClause. type. trimmedDescription)
198
221
return nil
199
222
}
@@ -538,12 +561,24 @@ public class ExportSwift {
538
561
switch associatedValue. type {
539
562
case . string, . int, . float, . double, . bool:
540
563
break
564
+ case . optional( let wrappedType) :
565
+ switch wrappedType {
566
+ case . string, . int, . float, . double, . bool:
567
+ break
568
+ default :
569
+ diagnose (
570
+ node: node,
571
+ message: " Unsupported associated value type: \( associatedValue. type. swiftType) " ,
572
+ hint:
573
+ " Only primitive types and optional primitives (String?, Int?, Float?, Double?, Bool?) are supported in associated-value enums "
574
+ )
575
+ }
541
576
default :
542
577
diagnose (
543
578
node: node,
544
579
message: " Unsupported associated value type: \( associatedValue. type. swiftType) " ,
545
580
hint:
546
- " Only primitive types (String, Int, Float, Double, Bool) are supported in associated-value enums "
581
+ " Only primitive types and optional primitives (String? , Int? , Float? , Double? , Bool? ) are supported in associated-value enums "
547
582
)
548
583
}
549
584
}
@@ -712,8 +747,46 @@ public class ExportSwift {
712
747
}
713
748
714
749
func lookupType( for type: TypeSyntax ) -> BridgeType ? {
715
- if let primitive = BridgeType ( swiftType: type. trimmedDescription) {
716
- return primitive
750
+ // T?
751
+ if let optionalType = type. as ( OptionalTypeSyntax . self) {
752
+ let wrappedType = optionalType. wrappedType
753
+ if let baseType = lookupType ( for: wrappedType) {
754
+ return . optional( baseType)
755
+ }
756
+ }
757
+ // Optional<T>
758
+ if let identifierType = type. as ( IdentifierTypeSyntax . self) ,
759
+ identifierType. name. text == " Optional " ,
760
+ let genericArgs = identifierType. genericArgumentClause? . arguments,
761
+ genericArgs. count == 1 ,
762
+ let argType = genericArgs. first? . argument
763
+ {
764
+ if let baseType = lookupType ( for: argType) {
765
+ return . optional( baseType)
766
+ }
767
+ }
768
+ // Swift.Optional<T>
769
+ if let memberType = type. as ( MemberTypeSyntax . self) ,
770
+ let baseType = memberType. baseType. as ( IdentifierTypeSyntax . self) ,
771
+ baseType. name. text == " Swift " ,
772
+ memberType. name. text == " Optional " ,
773
+ let genericArgs = memberType. genericArgumentClause? . arguments,
774
+ genericArgs. count == 1 ,
775
+ let argType = genericArgs. first? . argument
776
+ {
777
+ if let wrappedType = lookupType ( for: argType) {
778
+ return . optional( wrappedType)
779
+ }
780
+ }
781
+ if let aliasDecl = typeDeclResolver. resolveTypeAlias ( type) {
782
+ if let resolvedType = lookupType ( for: aliasDecl. initializer. value) {
783
+ return resolvedType
784
+ }
785
+ }
786
+
787
+ let typeName = type. trimmedDescription
788
+ if let primitiveType = BridgeType ( swiftType: typeName) {
789
+ return primitiveType
717
790
}
718
791
719
792
guard let typeDecl = typeDeclResolver. resolve ( type) else {
@@ -831,9 +904,18 @@ public class ExportSwift {
831
904
} else {
832
905
argumentsToLift = liftingInfo. parameters. map { ( name, _) in param. name + name. capitalizedFirstLetter }
833
906
}
907
+
908
+ let typeNameForIntrinsic : String
909
+ switch param. type {
910
+ case . optional( let wrappedType) :
911
+ typeNameForIntrinsic = " Optional< \( wrappedType. swiftType) > "
912
+ default :
913
+ typeNameForIntrinsic = param. type. swiftType
914
+ }
915
+
834
916
liftedParameterExprs. append (
835
917
ExprSyntax (
836
- " \( raw: param . type . swiftType ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
918
+ " \( raw: typeNameForIntrinsic ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
837
919
)
838
920
)
839
921
for (name, type) in zip ( argumentsToLift, liftingInfo. parameters. map { $0. type } ) {
@@ -1013,7 +1095,7 @@ public class ExportSwift {
1013
1095
let valueSwitch = ( [ " switch self { " ] + valueCases + [ " } " ] ) . joined ( separator: " \n " )
1014
1096
1015
1097
return """
1016
- extension \( raw: typeName) {
1098
+ extension \( raw: typeName) : _BridgedSwiftCaseEnum {
1017
1099
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
1018
1100
return bridgeJSRawValue
1019
1101
}
@@ -1041,15 +1123,15 @@ public class ExportSwift {
1041
1123
func renderAssociatedValueEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
1042
1124
let typeName = enumDef. swiftCallName
1043
1125
return """
1044
- private extension \( raw: typeName) {
1045
- static func bridgeJSLiftParameter(_ caseId: Int32) -> \( raw: typeName) {
1126
+ extension \( raw: typeName) : _BridgedSwiftAssociatedValueEnum {
1127
+ @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \( raw: typeName) {
1046
1128
switch caseId {
1047
1129
\( raw: generateStackLiftSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1048
1130
default: fatalError( " Unknown \( raw: typeName) case ID: \\ (caseId) " )
1049
1131
}
1050
1132
}
1051
1133
1052
- func bridgeJSLowerReturn() {
1134
+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() {
1053
1135
switch self {
1054
1136
\( raw: generateReturnSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
1055
1137
}
@@ -1085,6 +1167,26 @@ public class ExportSwift {
1085
1167
return " \( paramName) Float.bridgeJSLiftParameter(_swift_js_pop_param_f32()) "
1086
1168
case . double:
1087
1169
return " \( paramName) Double.bridgeJSLiftParameter(_swift_js_pop_param_f64()) "
1170
+ case . optional( let wrappedType) :
1171
+ switch wrappedType {
1172
+ case . string:
1173
+ return
1174
+ " \( paramName) Optional<String>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32(), _swift_js_pop_param_int32()) "
1175
+ case . int:
1176
+ return
1177
+ " \( paramName) Optional<Int>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32()) "
1178
+ case . bool:
1179
+ return
1180
+ " \( paramName) Optional<Bool>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32()) "
1181
+ case . float:
1182
+ return
1183
+ " \( paramName) Optional<Float>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_f32()) "
1184
+ case . double:
1185
+ return
1186
+ " \( paramName) Optional<Double>.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_f64()) "
1187
+ default :
1188
+ return " "
1189
+ }
1088
1190
default :
1089
1191
return " \( paramName) Int.bridgeJSLiftParameter(_swift_js_pop_param_int32()) "
1090
1192
}
@@ -1121,6 +1223,30 @@ public class ExportSwift {
1121
1223
bodyLines. append ( " _swift_js_push_f32( \( paramName) ) " )
1122
1224
case . double:
1123
1225
bodyLines. append ( " _swift_js_push_f64( \( paramName) ) " )
1226
+ case . optional( let wrappedType) :
1227
+ bodyLines. append ( " let __bjs_isSome_ \( paramName) = \( paramName) != nil " )
1228
+ bodyLines. append ( " if let __bjs_unwrapped_ \( paramName) = \( paramName) { " )
1229
+ switch wrappedType {
1230
+ case . string:
1231
+ bodyLines. append ( " var __bjs_str_ \( paramName) = __bjs_unwrapped_ \( paramName) " )
1232
+ bodyLines. append ( " __bjs_str_ \( paramName) .withUTF8 { ptr in " )
1233
+ bodyLines. append ( " _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) " )
1234
+ bodyLines. append ( " } " )
1235
+ case . int:
1236
+ bodyLines. append ( " _swift_js_push_int(Int32(__bjs_unwrapped_ \( paramName) )) " )
1237
+ case . bool:
1238
+ bodyLines. append ( " _swift_js_push_int(__bjs_unwrapped_ \( paramName) ? 1 : 0) " )
1239
+ case . float:
1240
+ bodyLines. append ( " _swift_js_push_f32(__bjs_unwrapped_ \( paramName) ) " )
1241
+ case . double:
1242
+ bodyLines. append ( " _swift_js_push_f64(__bjs_unwrapped_ \( paramName) ) " )
1243
+ default :
1244
+ bodyLines. append (
1245
+ " preconditionFailure( \" BridgeJS: unsupported optional wrapped type in generated code \" ) "
1246
+ )
1247
+ }
1248
+ bodyLines. append ( " } " )
1249
+ bodyLines. append ( " _swift_js_push_int(__bjs_isSome_ \( paramName) ? 1 : 0) " )
1124
1250
default :
1125
1251
bodyLines. append (
1126
1252
" preconditionFailure( \" BridgeJS: unsupported associated value type in generated code \" ) "
@@ -1377,6 +1503,7 @@ extension BridgeType {
1377
1503
case . jsObject( let name? ) : return name
1378
1504
case . swiftHeapObject( let name) : return name
1379
1505
case . void: return " Void "
1506
+ case . optional( let wrappedType) : return " Optional< \( wrappedType. swiftType) > "
1380
1507
case . caseEnum( let name) : return name
1381
1508
case . rawValueEnum( let name, _) : return name
1382
1509
case . associatedValueEnum( let name) : return name
@@ -1411,6 +1538,10 @@ extension BridgeType {
1411
1538
case . jsObject: return . jsObject
1412
1539
case . swiftHeapObject: return . swiftHeapObject
1413
1540
case . void: return . void
1541
+ case . optional( let wrappedType) :
1542
+ var optionalParams : [ ( name: String , type: WasmCoreType ) ] = [ ( " isSome " , . i32) ]
1543
+ optionalParams. append ( contentsOf: try wrappedType. liftParameterInfo ( ) . parameters)
1544
+ return LiftingIntrinsicInfo ( parameters: optionalParams)
1414
1545
case . caseEnum: return . caseEnum
1415
1546
case . rawValueEnum( _, let rawType) :
1416
1547
switch rawType {
@@ -1446,6 +1577,7 @@ extension BridgeType {
1446
1577
static let caseEnum = LoweringIntrinsicInfo ( returnType: . i32)
1447
1578
static let rawValueEnum = LoweringIntrinsicInfo ( returnType: . i32)
1448
1579
static let associatedValueEnum = LoweringIntrinsicInfo ( returnType: nil )
1580
+ static let optional = LoweringIntrinsicInfo ( returnType: nil )
1449
1581
}
1450
1582
1451
1583
func loweringReturnInfo( ) throws -> LoweringIntrinsicInfo {
@@ -1458,6 +1590,7 @@ extension BridgeType {
1458
1590
case . jsObject: return . jsObject
1459
1591
case . swiftHeapObject: return . swiftHeapObject
1460
1592
case . void: return . void
1593
+ case . optional: return . optional
1461
1594
case . caseEnum: return . caseEnum
1462
1595
case . rawValueEnum( _, let rawType) :
1463
1596
switch rawType {
0 commit comments