diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Tuples.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Tuples.swift index d92ad184a..c4679764d 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Tuples.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Tuples.swift @@ -24,6 +24,10 @@ public func labeledTuple() -> (x: Int32, y: Int32) { (x: 10, y: 20) } +public func echoSingleTuple(input: (String)) -> (String) { + input +} + public func echoTriple(triple: (Bool, Double, Int64)) -> (Bool, Double, Int64) { triple } diff --git a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java index cc89e1247..2b8351bc8 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java @@ -53,6 +53,13 @@ void labeledTuple() { Tuple2 check = result; } + @Test + void echoSingleTuple() { + var input = "Swift"; + String result = MySwiftLibrary.echoSingleTuple(input); + assertEquals(input, result); + } + @Test void echoTriple() { Tuple3 input = new Tuple3<>(true, 3.14, 100L); diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index 3e4b06c17..e6ad5e5f8 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -630,6 +630,17 @@ extension JNISwift2JavaGenerator { conversion: .typeMetadataAddress(.placeholder), ) + case .tuple(let elements) where elements.count == 1: + return try translateParameter( + swiftType: elements[0].type, + parameterName: parameterName, + methodName: methodName, + parentName: parentName, + genericParameters: genericParameters, + genericRequirements: genericRequirements, + parameterPosition: parameterPosition, + ) + case .tuple(let elements) where !elements.isEmpty: return try translateTupleParameter( elements: elements, @@ -1023,6 +1034,15 @@ extension JNISwift2JavaGenerator { case .tuple([]): return TranslatedResult(javaType: .void, nativeJavaType: .void, outParameters: [], conversion: .placeholder) + case .tuple(let elements) where elements.count == 1: + return try translateResult( + swiftType: elements[0].type, + methodName: methodName, + resultName: resultName, + genericParameters: genericParameters, + genericRequirements: genericRequirements, + ) + case .tuple(let elements) where !elements.isEmpty: return try translateTupleResult( methodName: methodName, @@ -1148,6 +1168,13 @@ extension JNISwift2JavaGenerator { } return .class(package: nil, name: generic.name) + case .tuple(let elements) where elements.count == 1: + return try translateGenericTypeParameter( + elements[0].type, + genericParameters: genericParameters, + genericRequirements: genericRequirements + ) + case .tuple(let elements): let elementJavaTypes = try elements.map { element in try translateGenericTypeParameter( diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index 0b210bbf5..890c8f26c 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -326,6 +326,16 @@ extension JNISwift2JavaGenerator { conversionCheck: nil ) + case .tuple(let elements) where elements.count == 1: + return try translateParameter( + type: elements[0].type, + parameterName: parameterName, + methodName: methodName, + parentName: parentName, + genericParameters: genericParameters, + genericRequirements: genericRequirements + ) + case .tuple(let elements) where !elements.isEmpty: return try translateTupleParameter( elements: elements, @@ -771,6 +781,9 @@ extension JNISwift2JavaGenerator { outParameters: [] ) + case .tuple(let elements) where elements.count == 1: + return try translateResult(swiftType: elements[0].type, methodName: methodName, resultName: resultName) + case .tuple(let elements) where !elements.isEmpty: return try translateTupleResult(methodName: methodName, elements: elements, resultName: resultName) diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple1.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple1.java deleted file mode 100644 index db1baa8e4..000000000 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple1.java +++ /dev/null @@ -1,46 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2025 Apple Inc. and the Swift.org project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Swift.org project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -package org.swift.swiftkit.core.tuple; - -/** - * Corresponds to Swift's built-in 1-element tuple type (T0). - * Elements are accessed via public final fields $0, $1, etc. - * @param the type of element 0 - */ -public class Tuple1 { - public final T0 $0; - - public Tuple1(T0 $0) { - this.$0 = $0; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (!(other instanceof Tuple1)) return false; - Tuple1 o = (Tuple1) other; - return java.util.Objects.equals(this.$0, o.$0); - } - - @Override - public int hashCode() { - return java.util.Objects.hash($0); - } - - @Override - public String toString() { - return "Tuple1(" + $0 + ")"; - } -} diff --git a/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift b/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift index ef90053fa..3e49daf08 100644 --- a/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift @@ -174,4 +174,61 @@ struct JNITupleTests { ] ) } + + @Test + func singleTuple() throws { + let input = """ + public func singleTuple(input: (String)) -> (String) { + input + } + """ + + try assertOutput( + input: input, + .jni, + .java, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + private static native java.lang.String $singleTuple(java.lang.String input); + """ + ] + ) + + try assertOutput( + input: input, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + public func Java_com_example_swift_SwiftModule__00024singleTuple__Ljava_lang_String_2(environment: UnsafeMutablePointer!, thisClass: jclass, input: jstring?) -> jstring? { + return SwiftModule.singleTuple(input: String(fromJNI: input, in: environment)).getJNILocalRefValue(in: environment) + } + """ + ] + ) + } + + @Test + func singleTupleInGeneric() throws { + let input = """ + public struct Box {} + public var singleTupleInGeneric: Box<(String)> { + "input" + } + """ + + try assertOutput( + input: input, + .jni, + .java, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + public static Box getSingleTupleInGeneric(SwiftArena swiftArena) + """ + ] + ) + } }