@@ -142,6 +142,14 @@ public class ExportSwift {
142
142
hint: " Only primitive types and types defined in the same module are allowed "
143
143
)
144
144
}
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
+ }
145
153
146
154
override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
147
155
switch state {
@@ -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
}
@@ -712,10 +735,53 @@ public class ExportSwift {
712
735
}
713
736
714
737
func lookupType( for type: TypeSyntax ) -> BridgeType ? {
715
- if let primitive = BridgeType ( swiftType: type. trimmedDescription) {
716
- return primitive
738
+ // 1. Handle T? syntax (OptionalTypeSyntax)
739
+ if let optionalType = type. as ( OptionalTypeSyntax . self) {
740
+ let wrappedType = optionalType. wrappedType
741
+ if let baseType = lookupType ( for: wrappedType) {
742
+ return . optional( baseType)
743
+ }
744
+ }
745
+
746
+ // 2. Handle Optional<T> syntax (IdentifierTypeSyntax with generic arguments)
747
+ if let identifierType = type. as ( IdentifierTypeSyntax . self) ,
748
+ identifierType. name. text == " Optional " ,
749
+ let genericArgs = identifierType. genericArgumentClause? . arguments,
750
+ genericArgs. count == 1 ,
751
+ let argType = genericArgs. first? . argument {
752
+ if let baseType = lookupType ( for: argType) {
753
+ return . optional( baseType)
754
+ }
755
+ }
756
+
757
+ // 3. Handle Swift.Optional<T> syntax (MemberTypeSyntax)
758
+ if let memberType = type. as ( MemberTypeSyntax . self) ,
759
+ let baseType = memberType. baseType. as ( IdentifierTypeSyntax . self) ,
760
+ baseType. name. text == " Swift " ,
761
+ memberType. name. text == " Optional " ,
762
+ let genericArgs = memberType. genericArgumentClause? . arguments,
763
+ genericArgs. count == 1 ,
764
+ let argType = genericArgs. first? . argument {
765
+ if let wrappedType = lookupType ( for: argType) {
766
+ return . optional( wrappedType)
767
+ }
768
+ }
769
+
770
+ // 4. Handle type aliases - try to resolve through type declaration resolver first
771
+ if let aliasDecl = typeDeclResolver. resolveTypeAlias ( type) {
772
+ // Recursively lookup the aliased type
773
+ if let resolvedType = lookupType ( for: aliasDecl. initializer. value) {
774
+ return resolvedType
775
+ }
717
776
}
718
777
778
+ // 5. Handle primitive types before falling back to other type declarations
779
+ let typeName = type. trimmedDescription
780
+ if let primitiveType = BridgeType . primitive ( swiftType: typeName) {
781
+ return primitiveType
782
+ }
783
+
784
+ // 6. Try to resolve other type declarations
719
785
guard let typeDecl = typeDeclResolver. resolve ( type) else {
720
786
return nil
721
787
}
@@ -831,9 +897,19 @@ public class ExportSwift {
831
897
} else {
832
898
argumentsToLift = liftingInfo. parameters. map { ( name, _) in param. name + name. capitalizedFirstLetter }
833
899
}
900
+
901
+ // For optional types, use Optional<WrappedType> syntax instead of WrappedType?
902
+ let typeNameForIntrinsic : String
903
+ switch param. type {
904
+ case . optional( let wrappedType) :
905
+ typeNameForIntrinsic = " Optional< \( wrappedType. swiftType) > "
906
+ default :
907
+ typeNameForIntrinsic = param. type. swiftType
908
+ }
909
+
834
910
liftedParameterExprs. append (
835
911
ExprSyntax (
836
- " \( raw: param . type . swiftType ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
912
+ " \( raw: typeNameForIntrinsic ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
837
913
)
838
914
)
839
915
for (name, type) in zip ( argumentsToLift, liftingInfo. parameters. map { $0. type } ) {
@@ -928,6 +1004,12 @@ public class ExportSwift {
928
1004
return
929
1005
}
930
1006
1007
+ // Handle optional types that use special storage functions and return Void
1008
+ if case . optional( _) = returnType {
1009
+ append ( " return ret.bridgeJSLowerReturn() " )
1010
+ return
1011
+ }
1012
+
931
1013
append ( " return ret.bridgeJSLowerReturn() " )
932
1014
}
933
1015
@@ -1085,6 +1167,8 @@ 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( _) :
1171
+ return " /* Optional associated value lifting not yet implemented */nil " // Placeholder
1088
1172
default :
1089
1173
return " \( paramName) Int.bridgeJSLiftParameter(_swift_js_pop_param_int32()) "
1090
1174
}
@@ -1121,6 +1205,8 @@ public class ExportSwift {
1121
1205
bodyLines. append ( " _swift_js_push_f32( \( paramName) ) " )
1122
1206
case . double:
1123
1207
bodyLines. append ( " _swift_js_push_f64( \( paramName) ) " )
1208
+ case . optional( _) :
1209
+ bodyLines. append ( " // Optional associated value lowering not yet implemented " ) // Placeholder
1124
1210
default :
1125
1211
bodyLines. append (
1126
1212
" preconditionFailure( \" BridgeJS: unsupported associated value type in generated code \" ) "
@@ -1331,24 +1417,55 @@ extension AttributeListSyntax {
1331
1417
}
1332
1418
1333
1419
extension BridgeType {
1420
+ // This initializer is primarily for string-based type descriptions,
1421
+ // especially for internal and raw type lookups.
1422
+ // For full SwiftSyntax based parsing, `ExportSwift.lookupType(for:)` should be used.
1334
1423
init ? ( swiftType: String ) {
1424
+ // Use SwiftSyntax to parse the string into a TypeSyntax for robust optional detection
1425
+ let typeSyntax = TypeSyntax ( stringLiteral: swiftType)
1426
+
1427
+ // 1. Handle T? syntax (OptionalTypeSyntax)
1428
+ if let optionalType = typeSyntax. as ( OptionalTypeSyntax . self) {
1429
+ let wrappedTypeString = optionalType. wrappedType. trimmedDescription
1430
+ if let baseType = BridgeType ( swiftType: wrappedTypeString) {
1431
+ self = . optional( baseType)
1432
+ return
1433
+ }
1434
+ }
1435
+
1436
+ // 2. Handle Optional<T> syntax (IdentifierTypeSyntax with generic arguments)
1437
+ if let identifierType = typeSyntax. as ( IdentifierTypeSyntax . self) ,
1438
+ identifierType. name. text == " Optional " ,
1439
+ let genericArgs = identifierType. genericArgumentClause? . arguments,
1440
+ genericArgs. count == 1 ,
1441
+ let argType = genericArgs. first? . argument {
1442
+ let innerTypeString = argType. trimmedDescription
1443
+ if let baseType = BridgeType ( swiftType: innerTypeString) {
1444
+ self = . optional( baseType)
1445
+ return
1446
+ }
1447
+ }
1448
+
1449
+ // Fallback to primitive type handling if not an optional
1450
+ if let primitive = BridgeType . primitive ( swiftType: swiftType) {
1451
+ self = primitive
1452
+ return
1453
+ }
1454
+
1455
+ return nil
1456
+ }
1457
+
1458
+ // Helper for direct primitive type mapping (used by init? and elsewhere)
1459
+ fileprivate static func primitive( swiftType: String ) -> BridgeType ? {
1335
1460
switch swiftType {
1336
- case " Int " :
1337
- self = . int
1338
- case " Float " :
1339
- self = . float
1340
- case " Double " :
1341
- self = . double
1342
- case " String " :
1343
- self = . string
1344
- case " Bool " :
1345
- self = . bool
1346
- case " Void " :
1347
- self = . void
1348
- case " JSObject " :
1349
- self = . jsObject( nil )
1350
- default :
1351
- return nil
1461
+ case " Int " : return . int
1462
+ case " Float " : return . float
1463
+ case " Double " : return . double
1464
+ case " String " : return . string
1465
+ case " Bool " : return . bool
1466
+ case " Void " : return . void
1467
+ case " JSObject " : return . jsObject( nil )
1468
+ default : return nil
1352
1469
}
1353
1470
}
1354
1471
}
@@ -1377,6 +1494,7 @@ extension BridgeType {
1377
1494
case . jsObject( let name? ) : return name
1378
1495
case . swiftHeapObject( let name) : return name
1379
1496
case . void: return " Void "
1497
+ case . optional( let wrappedType) : return " \( wrappedType. swiftType) ? "
1380
1498
case . caseEnum( let name) : return name
1381
1499
case . rawValueEnum( let name, _) : return name
1382
1500
case . associatedValueEnum( let name) : return name
@@ -1400,6 +1518,7 @@ extension BridgeType {
1400
1518
( " caseId " , . i32)
1401
1519
] )
1402
1520
}
1521
+
1403
1522
1404
1523
func liftParameterInfo( ) throws -> LiftingIntrinsicInfo {
1405
1524
switch self {
@@ -1411,6 +1530,11 @@ extension BridgeType {
1411
1530
case . jsObject: return . jsObject
1412
1531
case . swiftHeapObject: return . swiftHeapObject
1413
1532
case . void: return . void
1533
+ case . optional( let wrappedType) :
1534
+ // Optional parameters include optionality flag plus wrapped type parameters
1535
+ var optionalParams : [ ( name: String , type: WasmCoreType ) ] = [ ( " isSome " , . i32) ]
1536
+ optionalParams. append ( contentsOf: try wrappedType. liftParameterInfo ( ) . parameters)
1537
+ return LiftingIntrinsicInfo ( parameters: optionalParams)
1414
1538
case . caseEnum: return . caseEnum
1415
1539
case . rawValueEnum( _, let rawType) :
1416
1540
switch rawType {
@@ -1458,6 +1582,9 @@ extension BridgeType {
1458
1582
case . jsObject: return . jsObject
1459
1583
case . swiftHeapObject: return . swiftHeapObject
1460
1584
case . void: return . void
1585
+ case . optional( _) :
1586
+ // Optional return values use special storage functions and return void
1587
+ return LoweringIntrinsicInfo ( returnType: nil )
1461
1588
case . caseEnum: return . caseEnum
1462
1589
case . rawValueEnum( _, let rawType) :
1463
1590
switch rawType {
0 commit comments