@@ -191,7 +191,7 @@ extension FFMSwift2JavaGenerator {
191191 let translatedClosure = try translateFunctionType ( name: paramName, swiftType: funcTy, cdeclType: cdeclTy)
192192 funcTypes. append ( translatedClosure)
193193 case . tuple:
194- // TODO: Implement
194+ // Tuple-typed closure parameters are not supported (same as JNI / lowering).
195195 break
196196 default :
197197 break
@@ -462,9 +462,27 @@ extension FFMSwift2JavaGenerator {
462462 conversion: . swiftValueSelfSegment( . placeholder)
463463 )
464464
465- case . tuple:
466- // TODO: Implement.
467- throw JavaTranslationError . unhandledType ( swiftType)
465+ case . tuple( [ ] ) :
466+ return TranslatedParameter (
467+ javaParameters: [
468+ JavaParameter (
469+ name: parameterName,
470+ type: . void,
471+ annotations: parameterAnnotations
472+ )
473+ ] ,
474+ conversion: . placeholder
475+ )
476+
477+ case . tuple( let elements) :
478+ return try translateTupleParameter (
479+ elements: elements,
480+ convention: convention,
481+ parameterName: parameterName,
482+ methodName: methodName,
483+ genericParameters: genericParameters,
484+ genericRequirements: genericRequirements
485+ )
468486
469487 case . function:
470488 return TranslatedParameter (
@@ -539,6 +557,56 @@ extension FFMSwift2JavaGenerator {
539557 }
540558 }
541559
560+ /// Tuple parameters: one `TupleN<…>` on the Java API; conversion reads `.$0`, `.$1`, … (mirrors JNI).
561+ func translateTupleParameter(
562+ elements: [ SwiftTupleElement ] ,
563+ convention: SwiftParameterConvention ,
564+ parameterName: String ,
565+ methodName: String ,
566+ genericParameters: [ SwiftGenericParameterDeclaration ] ,
567+ genericRequirements: [ SwiftGenericRequirement ]
568+ ) throws -> TranslatedParameter {
569+ let lowering = CdeclLowering ( knownTypes: knownTypes)
570+ var elementJavaTypes : [ JavaType ] = [ ]
571+ var elementConversions : [ JavaConversionStep ] = [ ]
572+
573+ for (idx, element) in elements. enumerated ( ) {
574+ let subLowered = try lowering. lowerParameter (
575+ element. type,
576+ convention: convention,
577+ parameterName: " \( parameterName) _ \( idx) " ,
578+ genericParameters: genericParameters,
579+ genericRequirements: genericRequirements
580+ )
581+ let elementTranslated = try translateParameter (
582+ type: element. type,
583+ convention: convention,
584+ parameterName: " \( parameterName) _ \( idx) " ,
585+ loweredParam: subLowered,
586+ methodName: methodName,
587+ genericParameters: genericParameters,
588+ genericRequirements: genericRequirements
589+ )
590+ guard elementTranslated. javaParameters. count == 1 else {
591+ throw JavaTranslationError . unhandledType ( element. type)
592+ }
593+ let extraction = JavaConversionStep . replacingPlaceholder (
594+ elementTranslated. conversion,
595+ placeholder: " \( parameterName) .$ \( idx) "
596+ )
597+ elementConversions. append ( extraction)
598+ elementJavaTypes. append ( elementTranslated. javaParameters [ 0 ] . type. javaType)
599+ }
600+
601+ let javaType : JavaType = . tuple( elementTypes: elementJavaTypes)
602+ return TranslatedParameter (
603+ javaParameters: [
604+ JavaParameter ( name: parameterName, type: javaType)
605+ ] ,
606+ conversion: . commaSeparated( elementConversions)
607+ )
608+ }
609+
542610 /// Translate an Optional Swift API parameter to the user-facing Java API parameter.
543611 func translateOptionalParameter(
544612 wrappedType swiftType: SwiftType ,
@@ -722,9 +790,19 @@ extension FFMSwift2JavaGenerator {
722790 conversion: . wrapMemoryAddressUnsafe( . placeholder, javaType)
723791 )
724792
725- case . tuple:
726- // TODO: Implement.
727- throw JavaTranslationError . unhandledType ( swiftType)
793+ case . tuple( [ ] ) :
794+ return TranslatedResult (
795+ javaResultType: . void,
796+ annotations: resultAnnotations,
797+ outParameters: [ ] ,
798+ conversion: . placeholder
799+ )
800+
801+ case . tuple( let elements) :
802+ return try translateTupleResult (
803+ elements: elements,
804+ resultAnnotations: resultAnnotations
805+ )
728806
729807 case . array( let wrapped) where wrapped == knownTypes. uint8:
730808 return TranslatedResult (
@@ -782,6 +860,59 @@ extension FFMSwift2JavaGenerator {
782860
783861 }
784862
863+ /// Tuple results: indirect `MemorySegment` per element, then `new TupleN<…>(…)` (mirrors JNI out-arrays).
864+ func translateTupleResult(
865+ elements: [ SwiftTupleElement ] ,
866+ resultAnnotations: [ JavaAnnotation ]
867+ ) throws -> TranslatedResult {
868+ var outParameters : [ JavaParameter ] = [ ]
869+ var tupleElements : [ ( outParamName: String , elementConversion: JavaConversionStep ) ] = [ ]
870+ var elementJavaTypes : [ JavaType ] = [ ]
871+
872+ for (idx, element) in elements. enumerated ( ) {
873+ let ( javaType, elementConversion) = try translateTupleElementResult ( type: element. type)
874+ outParameters. append ( JavaParameter ( name: " \( idx) " , type: javaType) )
875+ tupleElements. append ( ( outParamName: " _result_ \( idx) " , elementConversion: elementConversion) )
876+ elementJavaTypes. append ( javaType)
877+ }
878+
879+ let javaResultType : JavaType = . tuple( elementTypes: elementJavaTypes)
880+ let fullTupleClassName = javaResultType. fullyQualifiedClassName!
881+
882+ return TranslatedResult (
883+ javaResultType: javaResultType,
884+ annotations: resultAnnotations,
885+ outParameters: outParameters,
886+ conversion: . tupleFromOutParams(
887+ tupleClassName: " new \( fullTupleClassName) " ,
888+ elements: tupleElements
889+ )
890+ )
891+ }
892+
893+ /// Single tuple element for the Java result (mirrors JNI `translateTupleElementResult`).
894+ private func translateTupleElementResult( type: SwiftType ) throws -> ( JavaType , JavaConversionStep ) {
895+ switch type {
896+ case . nominal( let nominalType) :
897+ if nominalType. nominalTypeDecl. knownTypeKind != nil {
898+ if let cType = try ? CType ( cdeclType: type) {
899+ return ( cType. javaType, . readMemorySegment( . placeholder, as: cType. javaType) )
900+ }
901+ throw JavaTranslationError . unhandledType ( type)
902+ }
903+
904+ guard !nominalType. isSwiftJavaWrapper else {
905+ throw JavaTranslationError . unhandledType ( type)
906+ }
907+
908+ let javaType : JavaType = . class( package : nil , name: nominalType. nominalTypeDecl. qualifiedName)
909+ return ( javaType, . wrapMemoryAddressUnsafe( . placeholder, javaType) )
910+
911+ default :
912+ throw JavaTranslationError . unhandledType ( type)
913+ }
914+ }
915+
785916 func translate(
786917 swiftType: SwiftType
787918 ) throws -> JavaType {
@@ -876,6 +1007,15 @@ extension FFMSwift2JavaGenerator {
8761007 /// Refer an exploded argument suffixed with `_\(name)`.
8771008 indirect case readMemorySegment( JavaConversionStep , as: JavaType )
8781009
1010+ /// Use `placeholder` as the root when rendering `inner` (same idea as JNI `replacingPlaceholder`).
1011+ indirect case replacingPlaceholder( JavaConversionStep , placeholder: String )
1012+
1013+ /// Build `org.swift.swiftkit.core.tuple.TupleN` from indirect `MemorySegment` out params (JNI `tupleFromOutParams`).
1014+ case tupleFromOutParams(
1015+ tupleClassName: String ,
1016+ elements: [ ( outParamName: String , elementConversion: JavaConversionStep ) ]
1017+ )
1018+
8791019 var isPlaceholder : Bool {
8801020 if case . placeholder = self { true } else { false }
8811021 }
0 commit comments