@@ -143,6 +143,14 @@ public class ExportSwift {
143143 )
144144 }
145145
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+ 146154 override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
147155 switch state {
148156 case . topLevel:
@@ -183,17 +191,32 @@ public class ExportSwift {
183191
184192 var parameters : [ Parameter ] = [ ]
185193 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 {
187202 diagnoseUnsupportedType ( node: param. type, type: param. type. trimmedDescription)
188203 continue
189204 }
205+ 190206 let name = param. secondName? . text ?? param. firstName. text
191207 let label = param. firstName. text
192208 parameters. append ( Parameter ( label: label, name: name, type: type) )
193209 }
194210 let returnType : BridgeType
195211 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 {
197220 diagnoseUnsupportedType ( node: returnClause. type, type: returnClause. type. trimmedDescription)
198221 return nil
199222 }
@@ -538,12 +561,24 @@ public class ExportSwift {
538561 switch associatedValue. type {
539562 case . string, . int, . float, . double, . bool:
540563 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+ }
541576 default :
542577 diagnose (
543578 node: node,
544579 message: " Unsupported associated value type: \( associatedValue. type. swiftType) " ,
545580 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 "
547582 )
548583 }
549584 }
@@ -712,8 +747,46 @@ public class ExportSwift {
712747 }
713748
714749 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
717790 }
718791
719792 guard let typeDecl = typeDeclResolver. resolve ( type) else {
@@ -831,9 +904,18 @@ public class ExportSwift {
831904 } else {
832905 argumentsToLift = liftingInfo. parameters. map { ( name, _) in param. name + name. capitalizedFirstLetter }
833906 }
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+ 834916 liftedParameterExprs. append (
835917 ExprSyntax (
836- " \( raw: param . type . swiftType ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
918+ " \( raw: typeNameForIntrinsic ) .bridgeJSLiftParameter( \( raw: argumentsToLift. joined ( separator: " , " ) ) ) "
837919 )
838920 )
839921 for (name, type) in zip ( argumentsToLift, liftingInfo. parameters. map { 0ドル. type } ) {
@@ -1013,7 +1095,7 @@ public class ExportSwift {
10131095 let valueSwitch = ( [ " switch self { " ] + valueCases + [ " } " ] ) . joined ( separator: " \n " )
10141096
10151097 return """
1016- extension \( raw: typeName) {
1098+ extension \( raw: typeName) : _BridgedSwiftCaseEnum {
10171099 @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
10181100 return bridgeJSRawValue
10191101 }
@@ -1041,15 +1123,15 @@ public class ExportSwift {
10411123 func renderAssociatedValueEnumHelpers( _ enumDef: ExportedEnum ) -> DeclSyntax {
10421124 let typeName = enumDef. swiftCallName
10431125 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) {
10461128 switch caseId {
10471129\( raw: generateStackLiftSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
10481130 default: fatalError( " Unknown \( raw: typeName) case ID: \\ (caseId) " )
10491131 }
10501132 }
10511133
1052- func bridgeJSLowerReturn() {
1134+ @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() {
10531135 switch self {
10541136\( raw: generateReturnSwitchCases ( enumDef: enumDef) . joined ( separator: " \n " ) )
10551137 }
@@ -1085,6 +1167,26 @@ public class ExportSwift {
10851167 return " \( paramName) Float.bridgeJSLiftParameter(_swift_js_pop_param_f32()) "
10861168 case . double:
10871169 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+ }
10881190 default :
10891191 return " \( paramName) Int.bridgeJSLiftParameter(_swift_js_pop_param_int32()) "
10901192 }
@@ -1121,6 +1223,30 @@ public class ExportSwift {
11211223 bodyLines. append ( " _swift_js_push_f32( \( paramName) ) " )
11221224 case . double:
11231225 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) " )
11241250 default :
11251251 bodyLines. append (
11261252 " preconditionFailure( \" BridgeJS: unsupported associated value type in generated code \" ) "
@@ -1377,6 +1503,7 @@ extension BridgeType {
13771503 case . jsObject( let name? ) : return name
13781504 case . swiftHeapObject( let name) : return name
13791505 case . void: return " Void "
1506+ case . optional( let wrappedType) : return " Optional< \( wrappedType. swiftType) > "
13801507 case . caseEnum( let name) : return name
13811508 case . rawValueEnum( let name, _) : return name
13821509 case . associatedValueEnum( let name) : return name
@@ -1411,6 +1538,10 @@ extension BridgeType {
14111538 case . jsObject: return . jsObject
14121539 case . swiftHeapObject: return . swiftHeapObject
14131540 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)
14141545 case . caseEnum: return . caseEnum
14151546 case . rawValueEnum( _, let rawType) :
14161547 switch rawType {
@@ -1446,6 +1577,7 @@ extension BridgeType {
14461577 static let caseEnum = LoweringIntrinsicInfo ( returnType: . i32)
14471578 static let rawValueEnum = LoweringIntrinsicInfo ( returnType: . i32)
14481579 static let associatedValueEnum = LoweringIntrinsicInfo ( returnType: nil )
1580+ static let optional = LoweringIntrinsicInfo ( returnType: nil )
14491581 }
14501582
14511583 func loweringReturnInfo( ) throws -> LoweringIntrinsicInfo {
@@ -1458,6 +1590,7 @@ extension BridgeType {
14581590 case . jsObject: return . jsObject
14591591 case . swiftHeapObject: return . swiftHeapObject
14601592 case . void: return . void
1593+ case . optional: return . optional
14611594 case . caseEnum: return . caseEnum
14621595 case . rawValueEnum( _, let rawType) :
14631596 switch rawType {
0 commit comments