@@ -579,11 +579,68 @@ extension JNISwift2JavaGenerator {
579579 conversion: . typeMetadataAddress( . placeholder)
580580 )
581581
582+ case . tuple( let elements) where !elements. isEmpty:
583+ return try translateTupleParameter (
584+ elements: elements,
585+ parameterName: parameterName,
586+ methodName: methodName,
587+ parentName: parentName,
588+ genericParameters: genericParameters,
589+ genericRequirements: genericRequirements,
590+ parameterPosition: parameterPosition
591+ )
592+
582593 case . tuple, . composite:
583594 throw JavaTranslationError . unsupportedSwiftType ( swiftType)
584595 }
585596 }
586597
598+ func translateTupleParameter(
599+ elements: [ SwiftTupleElement ] ,
600+ parameterName: String ,
601+ methodName: String ,
602+ parentName: String ,
603+ genericParameters: [ SwiftGenericParameterDeclaration ] ,
604+ genericRequirements: [ SwiftGenericRequirement ] ,
605+ parameterPosition: Int ?
606+ ) throws -> TranslatedParameter {
607+ let arity = elements. count
608+ var elementBoxedTypes : [ String ] = [ ]
609+
610+ // Generate a conversion that extracts each element from the Tuple record
611+ var elementConversions : [ JavaNativeConversionStep ] = [ ]
612+ for (idx, element) in elements. enumerated ( ) {
613+ let elementTranslated = try translateParameter (
614+ swiftType: element. type,
615+ parameterName: " \( parameterName) _ \( idx) " ,
616+ methodName: methodName,
617+ parentName: parentName,
618+ genericParameters: genericParameters,
619+ genericRequirements: genericRequirements,
620+ parameterPosition: parameterPosition
621+ )
622+
623+ // Extract the element from the tuple using .$N() accessor
624+ let extraction = JavaNativeConversionStep . replacingPlaceholder (
625+ elementTranslated. conversion,
626+ placeholder: " \( parameterName) .$ \( idx) () "
627+ )
628+ elementConversions. append ( extraction)
629+ elementBoxedTypes. append ( elementTranslated. parameter. type. javaType. boxedName)
630+ }
631+
632+ let genericParams = elementBoxedTypes. joined ( separator: " , " )
633+ let javaType : JavaType = . class( package : " org.swift.swiftkit.core.tuple " , name: " Tuple \( arity) < \( genericParams) > " )
634+
635+ return TranslatedParameter (
636+ parameter: JavaParameter (
637+ name: parameterName,
638+ type: javaType
639+ ) ,
640+ conversion: . commaSeparated( elementConversions)
641+ )
642+ }
643+
587644 func convertToAsync(
588645 translatedFunctionSignature: inout TranslatedFunctionSignature ,
589646 nativeFunctionSignature: inout NativeFunctionSignature ,
@@ -887,11 +944,83 @@ extension JNISwift2JavaGenerator {
887944 elementType: elementType
888945 )
889946
947+ case . tuple( let elements) where !elements. isEmpty:
948+ return try translateTupleResult ( elements: elements, resultName: resultName)
949+
890950 case . metatype, . tuple, . function, . existential, . opaque, . genericParameter, . composite:
891951 throw JavaTranslationError . unsupportedSwiftType ( swiftType)
892952 }
893953 }
894954
955+ func translateTupleResult(
956+ elements: [ SwiftTupleElement ] ,
957+ resultName: String = " result "
958+ ) throws -> TranslatedResult {
959+ let arity = elements. count
960+ var outParameters : [ OutParameter ] = [ ]
961+ var elementOutParamNames : [ String ] = [ ]
962+ var elementConversions : [ JavaNativeConversionStep ] = [ ]
963+ var elementBoxedTypes : [ String ] = [ ]
964+
965+ for (idx, element) in elements. enumerated ( ) {
966+ let outParamName = " \( resultName) _ \( idx) $ "
967+
968+ // Determine the Java type for this element
969+ let ( javaType, elementConversion) = try translateTupleElementResult ( type: element. type)
970+ let arrayType : JavaType = . array( javaType)
971+
972+ outParameters. append (
973+ OutParameter ( name: outParamName, type: arrayType, allocation: . newArray( javaType, size: 1 ) )
974+ )
975+ elementOutParamNames. append ( outParamName)
976+ elementConversions. append ( elementConversion)
977+ elementBoxedTypes. append ( javaType. boxedName)
978+ }
979+
980+ let genericParams = elementBoxedTypes. joined ( separator: " , " )
981+ let tupleClassName = " Tuple \( arity) < \( genericParams) > "
982+ let fullTupleClassName = " org.swift.swiftkit.core.tuple.Tuple \( arity) "
983+ let javaResultType : JavaType = . class( package : " org.swift.swiftkit.core.tuple " , name: tupleClassName)
984+
985+ let tupleElements : [ ( outParamName: String , elementConversion: JavaNativeConversionStep ) ] =
986+ zip ( elementOutParamNames, elementConversions) . map { ( $0, $1) }
987+
988+ return TranslatedResult (
989+ javaType: javaResultType,
990+ outParameters: outParameters,
991+ conversion: . tupleFromOutParams(
992+ tupleClassName: " new \( fullTupleClassName) <> " ,
993+ elements: tupleElements
994+ )
995+ )
996+ }
997+
998+ /// Translate a single element type for tuple results on the Java side.
999+ private func translateTupleElementResult( type: SwiftType ) throws -> ( JavaType , JavaNativeConversionStep ) {
1000+ switch type {
1001+ case . nominal( let nominalType) :
1002+ if let knownType = nominalType. nominalTypeDecl. knownTypeKind {
1003+ guard let javaType = JNIJavaTypeTranslator . translate ( knownType: knownType, config: self . config) else {
1004+ throw JavaTranslationError . unsupportedSwiftType ( type)
1005+ }
1006+ // Primitives: just read from array
1007+ return ( javaType, . placeholder)
1008+ }
1009+
1010+ let nominalTypeName = nominalType. nominalTypeDecl. name
1011+ guard !nominalType. isSwiftJavaWrapper else {
1012+ throw JavaTranslationError . unsupportedSwiftType ( type)
1013+ }
1014+
1015+ // JExtract class: wrap memory address
1016+ let javaType : JavaType = . class( package : nil , name: nominalTypeName)
1017+ return ( . long, . constructSwiftValue( . placeholder, javaType) )
1018+
1019+ default :
1020+ throw JavaTranslationError . unsupportedSwiftType ( type)
1021+ }
1022+ }
1023+
8951024 func translateOptionalResult(
8961025 wrappedType swiftType: SwiftType ,
8971026 resultName: String = " result "
@@ -1323,6 +1452,10 @@ extension JNISwift2JavaGenerator {
13231452
13241453 indirect case requireNonNull( JavaNativeConversionStep , message: String )
13251454
1455+ /// Constructs a TupleN from out-parameter arrays.
1456+ /// E.g. `new Tuple2<>(result_0$[0], result_1$[0])`
1457+ case tupleFromOutParams( tupleClassName: String , elements: [ ( outParamName: String , elementConversion: JavaNativeConversionStep ) ] )
1458+
13261459 /// `Arrays.stream(args)`
13271460 static func arraysStream( _ argument: JavaNativeConversionStep ) -> JavaNativeConversionStep {
13281461 . method( . constant( " Arrays " ) , function: " stream " , arguments: [ argument] )
@@ -1473,6 +1606,16 @@ extension JNISwift2JavaGenerator {
14731606 case . requireNonNull( let inner, let message) :
14741607 let inner = inner. render ( & printer, placeholder)
14751608 return #"Objects.requireNonNull( \#( inner) , " \#( message) ")"#
1609+
1610+ case . tupleFromOutParams( let tupleClassName, let elements) :
1611+ // Execute the native call first (the placeholder is the downcall expression)
1612+ printer. print ( " \( placeholder) ; " )
1613+ var args : [ String ] = [ ]
1614+ for element in elements {
1615+ let converted = element. elementConversion. render ( & printer, " \( element. outParamName) [0] " )
1616+ args. append ( converted)
1617+ }
1618+ return " \( tupleClassName) ( \( args. joined ( separator: " , " ) ) ) "
14761619 }
14771620 }
14781621
@@ -1535,6 +1678,9 @@ extension JNISwift2JavaGenerator {
15351678
15361679 case . requireNonNull( let inner, _) :
15371680 return inner. requiresSwiftArena
1681+
1682+ case . tupleFromOutParams( _, let elements) :
1683+ return elements. contains ( where: { $0. elementConversion. requiresSwiftArena } )
15381684 }
15391685 }
15401686 }
0 commit comments