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 4b8fa675c..a3ad4b197 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java +++ b/Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/TupleTest.java @@ -14,7 +14,6 @@ package com.example.swift; -import com.example.swift.MySwiftLibrary; import org.junit.jupiter.api.Test; import org.swift.swiftkit.core.tuple.Tuple2; import org.swift.swiftkit.core.tuple.Tuple3; @@ -38,9 +37,19 @@ void takePair() { @Test void labeledTuple() { - Tuple2 result = MySwiftLibrary.labeledTuple(); + var result = MySwiftLibrary.labeledTuple(); + // Access via named accessors + assertEquals(10, result.x()); + assertEquals(20, result.y()); + // Positional access still works (inherited from Tuple2) assertEquals(10, result.$0); assertEquals(20, result.$1); + + // The labelled tuple is a subclass of Tuple2 + assertInstanceOf(Tuple2.class, result); + // And the generic types match positionally as well + @SuppressWarnings("unused") + Tuple2 check = result; } @Test diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index c3b60943a..cb7eac727 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -388,10 +388,10 @@ extension FFMSwift2JavaGenerator { // If a Swift function is 'throws' we throw a checked error for the Java side // TODO: When we support typed throws on Swift side we'll want to throw the right type here instead if translatedSignature.isThrowing { - throwsClauses.append(JavaType.swiftJavaErrorException.simpleClassName) + throwsClauses.append(JavaType.swiftJavaErrorException.className!) } if translatedSignature.canThrowSwiftIntegerOverflowException { - throwsClauses.append(JavaType.swiftIntegerOverflowException.simpleClassName) + throwsClauses.append(JavaType.swiftIntegerOverflowException.className!) } let throwsClause = throwsClauses.isEmpty ? "" : " throws \(throwsClauses.joined(separator: ", "))" @@ -522,7 +522,7 @@ extension FFMSwift2JavaGenerator { func printErrorCheck(_ printer: inout CodePrinter) { guard translatedSignature.isThrowing else { return } printer.printIfBlock("!result$throws.get(ValueLayout.ADDRESS, 0).equals(MemorySegment.NULL)") { printer in - printer.print("throw new \(JavaType.swiftJavaErrorException.simpleClassName)(result$throws.get(ValueLayout.ADDRESS, 0), AllocatingSwiftArena.ofAuto());") + printer.print("throw new \(JavaType.swiftJavaErrorException.className!)(result$throws.get(ValueLayout.ADDRESS, 0), AllocatingSwiftArena.ofAuto());") } } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index bce460f66..c750fdc0a 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -335,7 +335,8 @@ extension FFMSwift2JavaGenerator { // Result. let result = try self.translateResult( swiftResult: swiftSignature.result, - loweredResult: loweredFunctionSignature.result + loweredResult: loweredFunctionSignature.result, + methodName: methodName ) return TranslatedFunctionSignature( @@ -620,8 +621,7 @@ extension FFMSwift2JavaGenerator { case .char: ("Optional", "toOptionalSegmentCharacter") case .short: ("Optional", "toOptionalSegmentShort") case .float: ("Optional", "toOptionalSegmentFloat") - default: - throw JavaTranslationError.unhandledType(known: .optional(swiftType)) + default: throw JavaTranslationError.unhandledType(known: .optional(swiftType)) } return TranslatedParameter( javaParameters: [ @@ -689,7 +689,8 @@ extension FFMSwift2JavaGenerator { /// Translate a Swift API result to the user-facing Java API result. func translateResult( swiftResult: SwiftResult, - loweredResult: LoweredResult + loweredResult: LoweredResult, + methodName: String ) throws -> TranslatedResult { let swiftType = swiftResult.type // If the result type should cause any annotations on the method, include them here. @@ -844,6 +845,7 @@ extension FFMSwift2JavaGenerator { case .tuple(let elements): return try translateTupleResult( + methodName: methodName, elements: elements, resultAnnotations: resultAnnotations ) @@ -856,6 +858,7 @@ extension FFMSwift2JavaGenerator { /// Tuple results: indirect `MemorySegment` per element, then `new TupleN<…>(…)` (mirrors JNI out-arrays). func translateTupleResult( + methodName: String, elements: [SwiftTupleElement], resultAnnotations: [JavaAnnotation] ) throws -> TranslatedResult { diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index 18dc222e4..6f5f1b8c6 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -151,7 +151,7 @@ extension FFMSwift2JavaGenerator { /// Returns the Java class name for a nominal type, applying known-type overrides func javaClassName(for decl: ImportedNominalType) -> String { if decl.swiftNominal.knownTypeKind == .swiftJavaError { - return JavaType.swiftJavaErrorException.simpleClassName + return JavaType.swiftJavaErrorException.className! } return decl.swiftNominal.name } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index 3a46d81d5..8f6d97a67 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -524,6 +524,10 @@ extension JNISwift2JavaGenerator { printJavaBindingWrapperHelperClass(&printer, decl) printJavaBindingWrapperMethod(&printer, decl, skipMethodBody: skipMethodBody) + + // Print any additional types we may need to emit, e.g. named tuples are emitted as static classes + // right next to the func that is using them. + printNecessarySupportTypes(&printer, decl) } /// Print the helper type container for a user-facing Java API. @@ -566,6 +570,17 @@ extension JNISwift2JavaGenerator { ) } + private func printNecessarySupportTypes( + _ printer: inout CodePrinter, + _ decl: ImportedFunc + ) { + let translatedDecl = translatedDecl(for: decl)! + + for labeledTuple in translatedDecl.usedLabeledTuples { + printAdHocLabeledTupleStaticClass(&printer, labeledTuple) + } + } + private func printJavaBindingWrapperMethod( _ printer: inout CodePrinter, _ decl: ImportedFunc, diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index 3cd1db3e0..69455ba69 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -115,12 +115,12 @@ extension JNISwift2JavaGenerator { let conversions = try enumCase.parameters.enumerated().map { idx, parameter in let resultName = parameter.name ?? "arg\(idx)" let result = SwiftResult(convention: .direct, type: parameter.type) - var translatedResult = try self.translate(swiftResult: result, resultName: resultName) + var translatedResult = try self.translate(swiftResult: result, methodName: methodName, resultName: resultName) translatedResult.conversion = .replacingPlaceholder( translatedResult.conversion, placeholder: "$nativeParameters.\(resultName)", ) - let nativeResult = try nativeTranslation.translate(swiftResult: result, resultName: resultName) + let nativeResult = try nativeTranslation.translate(swiftResult: result, methodName: methodName, resultName: resultName) return (translated: translatedResult, native: nativeResult) } @@ -319,7 +319,7 @@ extension JNISwift2JavaGenerator { ) } - let translatedResult = try translate(swiftResult: SwiftResult(convention: .direct, type: swiftType.resultType)) + let translatedResult = try translate(swiftResult: SwiftResult(convention: .direct, type: swiftType.resultType), methodName: name) return TranslatedFunctionType( name: name, @@ -367,6 +367,7 @@ extension JNISwift2JavaGenerator { let resultType = try translate( swiftResult: functionSignature.result, + methodName: methodName, genericParameters: functionSignature.genericParameters, genericRequirements: functionSignature.genericRequirements, ) @@ -628,7 +629,9 @@ extension JNISwift2JavaGenerator { parameterPosition: parameterPosition, ) - case .tuple, .composite: + case .tuple: + throw JavaTranslationError.emptyTuple() + case .composite: throw JavaTranslationError.unsupportedSwiftType(swiftType) } } @@ -885,6 +888,7 @@ extension JNISwift2JavaGenerator { func translate( swiftResult: SwiftResult, + methodName: String, resultName: String = "result", genericParameters: [SwiftGenericParameterDeclaration] = [], genericRequirements: [SwiftGenericRequirement] = [], @@ -1017,6 +1021,7 @@ extension JNISwift2JavaGenerator { case .tuple(let elements) where !elements.isEmpty: return try translateTupleResult( + methodName: methodName, elements: elements, resultName: resultName, genericParameters: genericParameters, @@ -1149,7 +1154,9 @@ extension JNISwift2JavaGenerator { } } + /// - Parameter: methodName is necessary because we may need to form an ad-hoc one off type if e.g. named tuples are used. func translateTupleResult( + methodName: String, elements: [SwiftTupleElement], resultName: String = "result", genericParameters: [SwiftGenericParameterDeclaration], @@ -1167,18 +1174,33 @@ extension JNISwift2JavaGenerator { // Determine the Java type for this element let elementResult = try translate( swiftResult: .init(convention: .indirect, type: element.type), + methodName: methodName, resultName: outParamName, genericParameters: genericParameters, genericRequirements: genericRequirements, ) + // out names are always ...$N, no need to use real named tuple names here, this is just for the thunk elementOutParamNames.append(outParamName) + // FIXME: More accurate determination of whether the result is direct or indirect if elementResult.outParameters.isEmpty { - // Convert direct result to indirect result - let arrayType: JavaType = .array(elementResult.javaType) + // Convert direct result to indirect result. + // For most class types (Swift wrapper classes), the JNI native representation + // is 'long' (a memory address). However, String is a native JNI reference + // type and must keep its original type so the out-parameter array matches + // the native method signature (String[] not long[]) + let nativeElementType: JavaType + if elementResult.javaType.isString { + nativeElementType = elementResult.javaType + } else if case .class = elementResult.javaType { + nativeElementType = .long + } else { + nativeElementType = elementResult.javaType + } + let arrayType: JavaType = .array(nativeElementType) outParameters.append( - OutParameter(name: outParamName, type: arrayType, allocation: .newArray(elementResult.javaType, size: 1)) + OutParameter(name: outParamName, type: arrayType, allocation: .newArray(nativeElementType, size: 1)) ) elementConversions.append(elementResult.conversion) } else { @@ -1188,19 +1210,36 @@ extension JNISwift2JavaGenerator { elementJavaTypes.append(elementResult.javaType) } - let javaResultType: JavaType = .tuple(elementTypes: elementJavaTypes) - let fullTupleClassName = "org.swift.swiftkit.core.tuple.Tuple\(arity)" + let isNamedTuple = elements.contains { $0.label != nil } + let names = elements.enumerated().map { idx, element in + if let label = element.label { + label + } else { + "$\(idx)" + } + } let tupleElements: [(outParamName: String, elementConversion: JavaNativeConversionStep)] = zip(elementOutParamNames, elementConversions).map { ($0, $1) } + let javaResultType: JavaType = + if isNamedTuple { + .labeledTuple(methodName, names: names, elementTypes: elementJavaTypes) + } else { + .tuple(elementTypes: elementJavaTypes) + } + + let javaNativeConversionStep: JavaNativeConversionStep = + .tupleFromOutParams( + // try!-safe, because we know the result type is a class here (a Tuple of some form) + tupleClassName: "\(javaResultType)", + elements: tupleElements + ) + return TranslatedResult( javaType: javaResultType, outParameters: outParameters, - conversion: .tupleFromOutParams( - tupleClassName: fullTupleClassName, - elements: tupleElements - ) + conversion: javaNativeConversionStep ) } @@ -1285,6 +1324,7 @@ extension JNISwift2JavaGenerator { let wrappedValueResult = try translate( swiftResult: SwiftResult(convention: .direct, type: swiftType), + methodName: "", resultName: resultName + "Wrapped$", genericParameters: genericParameters, genericRequirements: genericRequirements, @@ -1945,7 +1985,7 @@ extension JNISwift2JavaGenerator { let converted = element.elementConversion.render(&printer, "\(element.outParamName)[0]") args.append(converted) } - return "new \(tupleClassName)<>(\(args.joined(separator: ", ")))" + return "new \(tupleClassName)(\(args.joined(separator: ", ")))" case .placeToVar(let inner, let name): let inner = inner.render(&printer, placeholder) @@ -2025,6 +2065,7 @@ extension JNISwift2JavaGenerator { enum JavaTranslationError: Error { case unsupportedSwiftType(SwiftType, fileID: String, line: Int) + static func unsupportedSwiftType( _ type: SwiftType, _fileID: String = #fileID, @@ -2060,5 +2101,14 @@ extension JNISwift2JavaGenerator { /// Set type requires exactly one generic type argument (element). case setRequiresElementType(SwiftType) + + /// Empty tuples are not supported in lowering, they should be treated as Void + case emptyTuple(file: String, line: Int) + static func emptyTuple( + _file: String = #fileID, + _line: Int = #line + ) -> JavaTranslationError { + .emptyTuple(file: _file, line: _line) + } } } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+LabeledTuples.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+LabeledTuples.swift new file mode 100644 index 000000000..0250dd390 --- /dev/null +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+LabeledTuples.swift @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import CodePrinting +import SwiftJavaJNICore + +extension JNISwift2JavaGenerator { + + /// Print an ad-hoc static inner class for a labeled tuple type. + /// + /// Swift labeled tuples look like this: `(x: Int32, y: Int32)`. + /// + /// We need to produce a Java class that extends the positional `TupleN` and adds named accessor methods: + /// ```java + /// public static class LabeledTuple_fn_x_y + /// extends org.swift.swiftkit.core.tuple.Tuple2 { + /// + /// public LabeledTuple_fn_x_y(T0 param0, T1 param1) { super(param0, param1); } + /// public T0 x() { return $0; } + /// public T1 y() { return $1; } + /// } + /// ``` + func printAdHocLabeledTupleStaticClass( + _ printer: inout CodePrinter, + _ labeledTupleType: JavaType + ) { + guard labeledTupleType.isSwiftJavaLabeledTuple else { + return + } + guard case .class(_, let rawClassName, let genericArgs) = labeledTupleType else { + return + } + + let arity = genericArgs.count + let elementNames: [String] + + // Element names are embedded in the class name after "LabeledTuple__" + // We need to extract the last `arity` underscore-separated components + let parts = rawClassName.split(separator: "_") + // parts: ["LabeledTuple", baseName, name0, name1, ...] + // The first part is "LabeledTuple", second is baseName, rest are element names + if parts.count >= 2 + arity { + elementNames = parts.suffix(arity).map(String.init) + } else { + elementNames = (0.." + let baseTupleClass = "org.swift.swiftkit.core.tuple.Tuple\(arity)" + + // Constructor parameters: T0 param0, T1 param1, ... + // Use paramN names (not $0, $1) because `$N` is invalid as a Swift parameter name, + // and the wrap-java generator copies parameter names verbatim into Swift wrappers + let paramNames = (0.. NativeResult { let discriminatorName = "\(resultName)_discriminator$" @@ -592,6 +594,7 @@ extension JNISwift2JavaGenerator { convention: .direct, type: swiftType ), + methodName: methodName, resultName: resultName + "Wrapped" ) @@ -692,6 +695,7 @@ extension JNISwift2JavaGenerator { func translate( swiftResult: SwiftResult, + methodName: String, resultName: String = "result" ) throws -> NativeResult { switch swiftResult.type { @@ -699,7 +703,7 @@ extension JNISwift2JavaGenerator { if let knownType = nominalType.asKnownType { switch knownType { case .optional(let wrapped): - return try translateOptionalResult(wrappedType: wrapped, resultName: resultName) + return try translateOptionalResult(wrappedType: wrapped, methodName: methodName, resultName: resultName) case .array(let elementType): return try translateArrayResult(elementType: elementType, resultName: resultName) @@ -784,7 +788,7 @@ extension JNISwift2JavaGenerator { ) case .tuple(let elements) where !elements.isEmpty: - return try translateTupleResult(elements: elements, resultName: resultName) + return try translateTupleResult(methodName: methodName, elements: elements, resultName: resultName) case .metatype, .tuple, .function, .existential, .opaque, .genericParameter, .composite: throw JavaTranslationError.unsupportedSwiftType(swiftResult.type) @@ -792,6 +796,7 @@ extension JNISwift2JavaGenerator { } func translateTupleResult( + methodName: String, elements: [SwiftTupleElement], resultName: String ) throws -> NativeResult { @@ -804,6 +809,7 @@ extension JNISwift2JavaGenerator { // Get the JNI type for this element let elementResult = try translate( swiftResult: .init(convention: .indirect, type: element.type), + methodName: methodName, resultName: outParamName ) @@ -1076,7 +1082,7 @@ extension JNISwift2JavaGenerator { indirect case extractSwiftProtocolValue( NativeSwiftConversionStep, typeMetadataVariableName: NativeSwiftConversionStep, - protocolNames: [String] + protocolTypes: [SwiftNominalType] ) /// Extracts a swift type at a pointer given by a long. @@ -1164,8 +1170,8 @@ extension JNISwift2JavaGenerator { /// `SwiftType(inner)` indirect case labelessInitializer(NativeSwiftConversionStep, swiftType: SwiftType) - /// Converts a jbyteArray to UnsafeRawBufferPointer via GetByteArrayElements - indirect case jniByteArrayToUnsafeRawBufferPointer(NativeSwiftConversionStep, name: String) + /// Converts a jbyteArray to UnsafeRawBufferPointer or UnsafeMutableRawBufferPointer via GetByteArrayElements + indirect case jniByteArrayToUnsafeRawBufferPointer(NativeSwiftConversionStep, name: String, mutable: Bool) /// Constructs a Swift tuple from individually-converted elements. /// E.g. `(label0: conv0, conv1)` for `(label0: Int, String)` @@ -1222,12 +1228,10 @@ extension JNISwift2JavaGenerator { let protocolTypes, let allowsJavaImplementations ): - let protocolNames = protocolTypes.map { $0.nominalTypeDecl.qualifiedName } - let inner = inner.render(&printer, placeholder) let variableName = "\(inner)swiftObject$" - let compositeProtocolName = "(\(protocolNames.joined(separator: " & ")))" - printer.print("let \(variableName): \(compositeProtocolName)") + let existentialType = SwiftKitPrinting.renderExistentialType(protocolTypes) + printer.print("let \(variableName): \(existentialType)") func printStandardJExtractBlock(_ printer: inout CodePrinter) { let pointerVariableName = "\(inner)pointer$" @@ -1241,7 +1245,7 @@ extension JNISwift2JavaGenerator { let existentialName = NativeSwiftConversionStep.extractSwiftProtocolValue( .constant(pointerVariableName), typeMetadataVariableName: .constant(typeMetadataVariableName), - protocolNames: protocolNames + protocolTypes: protocolTypes ).render(&printer, placeholder) printer.print("\(variableName) = \(existentialName)") @@ -1270,12 +1274,12 @@ extension JNISwift2JavaGenerator { return variableName - case .extractSwiftProtocolValue(let inner, let typeMetadataVariableName, let protocolNames): + case .extractSwiftProtocolValue(let inner, let typeMetadataVariableName, let protocolTypes): let inner = inner.render(&printer, placeholder) let typeMetadataVariableName = typeMetadataVariableName.render(&printer, placeholder) let existentialName = "\(inner)Existential$" - let compositeProtocolName = "(\(protocolNames.joined(separator: " & ")))" + let existentialType = SwiftKitPrinting.renderExistentialType(protocolTypes) // TODO: Remove the _openExistential when we decide to only support language mode v6+ printer.print( @@ -1288,10 +1292,10 @@ extension JNISwift2JavaGenerator { fatalError("\(inner) memory address was null") } #if hasFeature(ImplicitOpenExistentials) - let \(existentialName) = \(inner)RawPointer$.load(as: \(inner)DynamicType$) as! any \(compositeProtocolName) + let \(existentialName) = \(inner)RawPointer$.load(as: \(inner)DynamicType$) as! \(existentialType) #else - func \(inner)DoLoad(_ ty: Ty.Type) -> any \(compositeProtocolName) { - \(inner)RawPointer$.load(as: ty) as! any \(compositeProtocolName) + func \(inner)DoLoad(_ ty: Ty.Type) -> \(existentialType) { + \(inner)RawPointer$.load(as: ty) as! \(existentialType) } let \(existentialName) = _openExistential(\(inner)DynamicType$, do: \(inner)DoLoad) #endif @@ -1726,17 +1730,19 @@ extension JNISwift2JavaGenerator { let inner = inner.render(&printer, placeholder) return "\(swiftType)(\(inner))" - case .jniByteArrayToUnsafeRawBufferPointer(let inner, let name): + case .jniByteArrayToUnsafeRawBufferPointer(let inner, let name, let mutable): let inner = inner.render(&printer, placeholder) let countVar = "\(name)$count" let ptrVar = "\(name)$ptr" let rbpVar = "\(name)$rbp" + let bufferPointerType = mutable ? "UnsafeMutableRawBufferPointer" : "UnsafeRawBufferPointer" + let releaseMode = mutable ? "0" : "jint(JNI_ABORT)" printer.print( """ let \(countVar) = Int(environment.interface.GetArrayLength(environment, \(inner))) let \(ptrVar) = environment.interface.GetByteArrayElements(environment, \(inner), nil)! - defer { environment.interface.ReleaseByteArrayElements(environment, \(inner), \(ptrVar), jint(JNI_ABORT)) } - let \(rbpVar) = UnsafeRawBufferPointer(start: \(ptrVar), count: \(countVar)) + defer { environment.interface.ReleaseByteArrayElements(environment, \(inner), \(ptrVar), \(releaseMode)) } + let \(rbpVar) = \(bufferPointerType)(start: \(ptrVar), count: \(countVar)) """ ) return rbpVar diff --git a/Sources/JExtractSwiftLib/JNI/TranslatedFunctionDecl+NamedTuples.swift b/Sources/JExtractSwiftLib/JNI/TranslatedFunctionDecl+NamedTuples.swift new file mode 100644 index 000000000..cd0236fa5 --- /dev/null +++ b/Sources/JExtractSwiftLib/JNI/TranslatedFunctionDecl+NamedTuples.swift @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +extension JNISwift2JavaGenerator.TranslatedFunctionDecl { + + /// Returns any used labeled tuple types that this function uses + var usedLabeledTuples: [JavaType] { + var result: [JavaType] = [] + collectLabeledTuples(from: translatedFunctionSignature.resultType.javaType, into: &result) + for param in translatedFunctionSignature.parameters { + collectLabeledTuples(from: param.parameter.type.javaType, into: &result) + } + return result + } +} + +private func collectLabeledTuples(from type: JavaType, into result: inout [JavaType]) { + switch type { + case .class(_, _, let typeParameters): + if type.isSwiftJavaLabeledTuple { + result.append(type) + } + for ty in typeParameters { + collectLabeledTuples(from: ty, into: &result) + } + case .array(let element): + collectLabeledTuples(from: element, into: &result) + default: + break + } +} diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+Collections.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Collections.swift new file mode 100644 index 000000000..18f59fa4d --- /dev/null +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Collections.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +extension JavaType { + + /// The description of the type org.swift.swiftkit.core.collections.SwiftDictionaryMap + static func swiftDictionaryMap(_ K: JavaType, _ V: JavaType) -> JavaType { + .class(package: "org.swift.swiftkit.core.collections", name: "SwiftDictionaryMap", typeParameters: [K.boxedType, V.boxedType]) + } + + /// The description of the type org.swift.swiftkit.core.collections.SwiftSet + static func swiftSet(_ E: JavaType) -> JavaType { + .class(package: "org.swift.swiftkit.core.collections", name: "SwiftSet", typeParameters: [E.boxedType]) + } +} diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+Exceptions.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Exceptions.swift new file mode 100644 index 000000000..a32d8dc72 --- /dev/null +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Exceptions.swift @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +extension JavaType { + + /// The Java exception type for the Swift error wrapper + static var swiftJavaErrorException: JavaType { + .class(package: "org.swift.swiftkit.ffm.generated", name: "SwiftJavaErrorException") + } + + /// The Java exception type for integer overflow checks + static var swiftIntegerOverflowException: JavaType { + .class(package: "org.swift.swiftkit.core", name: "SwiftIntegerOverflowException") + } + +} diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+Futures.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Futures.swift new file mode 100644 index 000000000..3492a3980 --- /dev/null +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Futures.swift @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +extension JavaType { + + /// The description of the type org.swift.swiftkit.core.SimpleCompletableFuture + static func simpleCompletableFuture(_ T: JavaType) -> JavaType { + .class(package: "org.swift.swiftkit.core", name: "SimpleCompletableFuture", typeParameters: [T.boxedType]) + } +} diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift index 87e774812..850768c25 100644 --- a/Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift @@ -16,57 +16,9 @@ import SwiftJavaJNICore extension JavaType { - /// The description of the type org.swift.swiftkit.core.SimpleCompletableFuture - static func simpleCompletableFuture(_ T: JavaType) -> JavaType { - .class(package: "org.swift.swiftkit.core", name: "SimpleCompletableFuture", typeParameters: [T.boxedType]) - } - - /// The maximum supported tuple arity. - static let maxTupleArity = 24 - - /// The description of the type org.swift.swiftkit.core.tuple.TupleN - static func tuple(elementTypes: [JavaType]) -> JavaType { - let arity = elementTypes.count - guard arity <= maxTupleArity else { - fatalError("Tuple arity \(arity) exceeds maximum supported arity of \(maxTupleArity)") - } - let genericParams = elementTypes.map(\.boxedName).joined(separator: ", ") - return .class(package: "org.swift.swiftkit.core.tuple", name: "Tuple\(arity)<\(genericParams)>") - } - - /// The description of the type org.swift.swiftkit.core.collections.SwiftDictionaryMap - static func swiftDictionaryMap(_ K: JavaType, _ V: JavaType) -> JavaType { - .class(package: "org.swift.swiftkit.core.collections", name: "SwiftDictionaryMap", typeParameters: [K.boxedType, V.boxedType]) - } - - /// The description of the type org.swift.swiftkit.core.collections.SwiftSet - static func swiftSet(_ E: JavaType) -> JavaType { - .class(package: "org.swift.swiftkit.core.collections", name: "SwiftSet", typeParameters: [E.boxedType]) - } - /// A container for receiving Swift generic instances. static var _OutSwiftGenericInstance: JavaType { .class(package: "org.swift.swiftkit.core", name: "_OutSwiftGenericInstance") } - // ==== ------------------------------------------------------------------- - // MARK: Exception types - - /// The Java exception type for the Swift error wrapper - static var swiftJavaErrorException: JavaType { - .class(package: "org.swift.swiftkit.ffm.generated", name: "SwiftJavaErrorException") - } - - /// The Java exception type for integer overflow checks - static var swiftIntegerOverflowException: JavaType { - .class(package: "org.swift.swiftkit.core", name: "SwiftIntegerOverflowException") - } - - /// Extract the simple class name from a `.class` JavaType - var simpleClassName: String { - switch self { - case .class(_, let name, _): name - default: fatalError("simpleClassName is only available for .class types, was: \(self)") - } - } } diff --git a/Sources/JExtractSwiftLib/JavaTypes/JavaType+Tuples.swift b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Tuples.swift new file mode 100644 index 000000000..99641a4ab --- /dev/null +++ b/Sources/JExtractSwiftLib/JavaTypes/JavaType+Tuples.swift @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +extension JavaType { + + /// The maximum supported tuple arity. + static let maxTupleArity = 24 + + /// The description of the type org.swift.swiftkit.core.tuple.TupleN + static func tuple(elementTypes: [JavaType]) -> JavaType { + let arity = elementTypes.count + guard arity <= maxTupleArity else { + fatalError("Tuple arity \(arity) exceeds maximum supported arity of \(maxTupleArity)") + } + return .class( + package: "org.swift.swiftkit.core.tuple", + name: "Tuple\(arity)", + typeParameters: elementTypes.map(\.boxedType) + ) + } + + /// The description of a labeled tuple type: LabeledTuple_someName_a_b_c + static func labeledTuple(_ baseName: String, names: [String], elementTypes: [JavaType]) -> JavaType { + assert(names.count == elementTypes.count, "Names count (\(names.count)) must be equal types count (\(elementTypes.count))") + + let arity = elementTypes.count + guard arity <= maxTupleArity else { + fatalError("Tuple arity \(arity) exceeds maximum supported arity of \(maxTupleArity)") + } + let joinedNames = names.joined(separator: "_") + return .class( + package: nil, + name: "LabeledTuple_\(baseName)_\(joinedNames)", + typeParameters: elementTypes.map(\.boxedType) + ) + } + + /// Whether this type is a labeled tuple type generated by swift-java + var isSwiftJavaLabeledTuple: Bool { + if case .class(_, let name, _) = self { + return name.hasPrefix("LabeledTuple_") + } + return false + } +} diff --git a/Sources/JExtractSwiftLib/SwiftKit+Printing.swift b/Sources/JExtractSwiftLib/SwiftKit+Printing.swift index 0afc96452..b8ceb6047 100644 --- a/Sources/JExtractSwiftLib/SwiftKit+Printing.swift +++ b/Sources/JExtractSwiftLib/SwiftKit+Printing.swift @@ -26,9 +26,23 @@ package struct SwiftKitPrinting { SwiftRuntime.swiftjava.getType("\(module)", "\(nominal.swiftNominal.qualifiedName)") """ } + + /// Render a parenthesized existential type constraint from nominal protocol types + /// + /// For a single protocol: `(any DataProtocol)` + /// For multiple protocols: `(any (DataProtocol & Sendable))` + static func renderExistentialType(_ protocolTypes: [SwiftNominalType]) -> String { + let compositeType: SwiftType + if protocolTypes.count == 1 { + compositeType = .nominal(protocolTypes[0]) + } else { + compositeType = .composite(protocolTypes.map { .nominal($0) }) + } + return "(\(SwiftType.existential(compositeType)))" + } } -// ==== ------------------------------------------------------------------------ +// ==== ----------------------------------------------------------------------- // Helpers to form names of "well known" SwiftKit generated functions extension SwiftKitPrinting { diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift index 5a12376f0..0de2ca191 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift @@ -167,9 +167,19 @@ extension SwiftType: CustomStringConvertible { case .tuple(let elements): return "(\(elements.map(\.description).joined(separator: ", ")))" case .existential(let constraintType): - return "any \(constraintType)" + switch constraintType { + case .composite: + return "any (\(constraintType))" + default: + return "any \(constraintType)" + } case .opaque(let constraintType): - return "some \(constraintType)" + switch constraintType { + case .composite: + return "some (\(constraintType))" + default: + return "some \(constraintType)" + } case .composite(let types): return types.map(\.description).joined(separator: " & ") } diff --git a/Sources/SwiftJavaToolLib/JavaTranslator.swift b/Sources/SwiftJavaToolLib/JavaTranslator.swift index 03a5e557d..0020e99a2 100644 --- a/Sources/SwiftJavaToolLib/JavaTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaTranslator.swift @@ -106,7 +106,6 @@ package class JavaTranslator { } } -// MARK: Defaults extension JavaTranslator { /// Default formatting options. private static let defaultFormat = BasicFormat(indentationWidth: .spaces(2)) 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 index 45fc8253d..6629c500b 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple1.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple1.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 1-element tuple type (T0). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple1 { +public class Tuple1 { public final T0 $0; public Tuple1(T0 $0) { diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple10.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple10.java index 1bc978d61..7adc90d94 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple10.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple10.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 10-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple10 { +public class Tuple10 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple11.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple11.java index df3ab5755..5e6520a5d 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple11.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple11.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 11-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple11 { +public class Tuple11 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple12.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple12.java index 10b6dc5d6..a916665e3 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple12.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple12.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 12-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple12 { +public class Tuple12 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple13.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple13.java index 8b3f71366..dc31991ea 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple13.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple13.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 13-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple13 { +public class Tuple13 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple14.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple14.java index f6dceaf09..dca55eb54 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple14.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple14.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 14-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple14 { +public class Tuple14 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple15.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple15.java index 32efe7178..9f8edd9a8 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple15.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple15.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 15-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple15 { +public class Tuple15 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple16.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple16.java index 62b6933b8..ba76df9e3 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple16.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple16.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 16-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple16 { +public class Tuple16 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple17.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple17.java index e38f3c328..557d26706 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple17.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple17.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 17-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple17 { +public class Tuple17 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple18.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple18.java index 7f7f6ba35..1324e0efa 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple18.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple18.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 18-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple18 { +public class Tuple18 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple19.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple19.java index aac156b74..c7651ed19 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple19.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple19.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 19-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple19 { +public class Tuple19 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple2.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple2.java index d437ef437..9bb14bbbe 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple2.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple2.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 2-element tuple type (T0, T1). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple2 { +public class Tuple2 { public final T0 $0; public final T1 $1; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple20.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple20.java index 9daa810b0..a65c7fb6e 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple20.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple20.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 20-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple20 { +public class Tuple20 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple21.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple21.java index 552b6b676..061128d0b 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple21.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple21.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 21-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple21 { +public class Tuple21 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple22.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple22.java index 42545d859..1e3a1bfd0 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple22.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple22.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 22-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple22 { +public class Tuple22 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple23.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple23.java index 1df45d0af..d0c981d06 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple23.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple23.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 23-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple23 { +public class Tuple23 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple24.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple24.java index 30a7dbf25..62923bef7 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple24.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple24.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 24-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple24 { +public class Tuple24 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple3.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple3.java index 513af2efb..0717c65c8 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple3.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple3.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 3-element tuple type (T0, T1, T2). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple3 { +public class Tuple3 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple4.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple4.java index ca3943905..781bc3561 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple4.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple4.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 4-element tuple type (T0, T1, T2, T3). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple4 { +public class Tuple4 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple5.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple5.java index ac592e7f9..173b9ba72 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple5.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple5.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 5-element tuple type (T0, T1, T2, T3, T4). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple5 { +public class Tuple5 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple6.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple6.java index c0a705d11..ebe44ecd0 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple6.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple6.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 6-element tuple type (T0, T1, T2, T3, T4, T5). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple6 { +public class Tuple6 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple7.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple7.java index 8ac584380..d40fc1799 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple7.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple7.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 7-element tuple type (T0, T1, T2, T3, T4, T5, T6). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple7 { +public class Tuple7 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple8.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple8.java index 85b78ec23..10261c8ca 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple8.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple8.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 8-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple8 { +public class Tuple8 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple9.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple9.java index 3823a1193..d4ba4c253 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple9.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/tuple/Tuple9.java @@ -18,7 +18,7 @@ * Corresponds to Swift's built-in 9-element tuple type (T0, T1, T2, T3, T4, T5, T6, T7, T8). * Elements are accessed via public final fields $0, $1, etc. */ -public final class Tuple9 { +public class Tuple9 { public final T0 $0; public final T1 $1; public final T2 $2; diff --git a/Tests/JExtractSwiftTests/FFM/FFMTupleTests.swift b/Tests/JExtractSwiftTests/FFM/FFMTupleTests.swift index 1b0c09b57..67fd0ab18 100644 --- a/Tests/JExtractSwiftTests/FFM/FFMTupleTests.swift +++ b/Tests/JExtractSwiftTests/FFM/FFMTupleTests.swift @@ -31,12 +31,12 @@ struct FFMTupleTests { .java, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2 returnPair() { + public static org.swift.swiftkit.core.tuple.Tuple2 returnPair() { try(var arena$ = Arena.ofConfined()) { MemorySegment result$_0 = arena$.allocate(SwiftValueLayout.SWIFT_INT64); MemorySegment result$_1 = arena$.allocate(SwiftValueLayout.SWIFT_INT64); swiftjava_SwiftModule_returnPair.call(result$_0, result$_1); - return new org.swift.swiftkit.core.tuple.Tuple2(result$_0.get(SwiftValueLayout.SWIFT_INT64, 0), result$_1.get(SwiftValueLayout.SWIFT_INT64, 0)); + return new org.swift.swiftkit.core.tuple.Tuple2(result$_0.get(SwiftValueLayout.SWIFT_INT64, 0), result$_1.get(SwiftValueLayout.SWIFT_INT64, 0)); } } """ @@ -53,7 +53,7 @@ struct FFMTupleTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static void takePair(org.swift.swiftkit.core.tuple.Tuple2 arg) { + public static void takePair(org.swift.swiftkit.core.tuple.Tuple2 arg) { swiftjava_SwiftModule_takePair__.call(arg.$0, arg.$1); } """ @@ -69,10 +69,10 @@ struct FFMTupleTests { .java, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2 labeledTuple() { + public static org.swift.swiftkit.core.tuple.Tuple2 labeledTuple() { """, """ - return new org.swift.swiftkit.core.tuple.Tuple2(result$_0.get(SwiftValueLayout.SWIFT_INT32, 0), result$_1.get(SwiftValueLayout.SWIFT_INT32, 0)); + return new org.swift.swiftkit.core.tuple.Tuple2(result$_0.get(SwiftValueLayout.SWIFT_INT32, 0), result$_1.get(SwiftValueLayout.SWIFT_INT32, 0)); """, ] ) diff --git a/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift b/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift index 897a2103d..57651e1e1 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIGenericCombinationTests.swift @@ -171,13 +171,13 @@ struct JNIGenericCombinationTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2, MyID> makeIDs(java.lang.String stringValue, long intValue, SwiftArena swiftArena) { + public static org.swift.swiftkit.core.tuple.Tuple2, MyID> makeIDs(java.lang.String stringValue, long intValue, SwiftArena swiftArena) { org.swift.swiftkit.core._OutSwiftGenericInstance result_0$ = new org.swift.swiftkit.core._OutSwiftGenericInstance(); org.swift.swiftkit.core._OutSwiftGenericInstance result_1$ = new org.swift.swiftkit.core._OutSwiftGenericInstance(); SwiftModule.$makeIDs(stringValue, intValue, result_0$, result_1$); var result_0 = MyID.wrapMemoryAddressUnsafe(result_0$.selfPointer, result_0$.selfTypePointer, swiftArena); var result_1 = MyID.wrapMemoryAddressUnsafe(result_1$.selfPointer, result_1$.selfTypePointer, swiftArena); - return new org.swift.swiftkit.core.tuple.Tuple2<>(result_0, result_1); + return new org.swift.swiftkit.core.tuple.Tuple2, MyID>(result_0, result_1); } """, """ @@ -233,12 +233,12 @@ struct JNIGenericCombinationTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2 takeValues(org.swift.swiftkit.core.tuple.Tuple2, MyID> tuple) { + public static org.swift.swiftkit.core.tuple.Tuple2 takeValues(org.swift.swiftkit.core.tuple.Tuple2, MyID> tuple) { java.lang.String[] result_0$ = new java.lang.String[1]; long[] result_1$ = new long[1]; SwiftModule.$takeValues(tuple.$0.$memoryAddress(), tuple.$1.$memoryAddress(), result_0$, result_1$); - return new org.swift.swiftkit.core.tuple.Tuple2<>(result_0$[0], result_1$[0]); - } + return new org.swift.swiftkit.core.tuple.Tuple2(result_0$[0], result_1$[0]); + } """, """ private static native void $takeValues(long tuple_0, long tuple_1, java.lang.String[] result_0$, long[] result_1$); diff --git a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift index 526c89675..6e763172b 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift @@ -133,7 +133,7 @@ struct JNIProtocolTests { """ @_cdecl("Java_com_example_swift_SwiftModule__00024takeProtocol__Ljava_lang_Object_2Ljava_lang_Object_2") public func Java_com_example_swift_SwiftModule__00024takeProtocol__Ljava_lang_Object_2Ljava_lang_Object_2(environment: UnsafeMutablePointer!, thisClass: jclass, x: jobject?, y: jobject?) { - let xswiftObject$: (SomeProtocol) + let xswiftObject$: (any SomeProtocol) if environment.interface.IsInstanceOf(environment, x, _JNIMethodIDCache.JNISwiftInstance.class) != 0 { ... let xpointer$DynamicType$: Any.Type = unsafeBitCast(xpointer$TypeMetadataPointer$, to: Any.Type.self) @@ -141,10 +141,10 @@ struct JNIProtocolTests { fatalError("xpointer$ memory address was null") } #if hasFeature(ImplicitOpenExistentials) - let xpointer$Existential$ = xpointer$RawPointer$.load(as: xpointer$DynamicType$) as! any (SomeProtocol) + let xpointer$Existential$ = xpointer$RawPointer$.load(as: xpointer$DynamicType$) as! (any SomeProtocol) #else - func xpointer$DoLoad(_ ty: Ty.Type) -> any (SomeProtocol) { - xpointer$RawPointer$.load(as: ty) as! any (SomeProtocol) + func xpointer$DoLoad(_ ty: Ty.Type) -> (any SomeProtocol) { + xpointer$RawPointer$.load(as: ty) as! (any SomeProtocol) } let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) #endif @@ -153,7 +153,7 @@ struct JNIProtocolTests { else { xswiftObject$ = _SwiftModule_takeProtocol_x_Wrapper(_javaSomeProtocolInterface: JavaSomeProtocol(javaThis: x!, environment: environment)) } - let yswiftObject$: (SomeProtocol) + let yswiftObject$: (any SomeProtocol) if environment.interface.IsInstanceOf(environment, y, _JNIMethodIDCache.JNISwiftInstance.class) != 0 { ... yswiftObject$ = ypointer$Existential$ @@ -209,7 +209,7 @@ struct JNIProtocolTests { """ @_cdecl("Java_com_example_swift_SwiftModule__00024takeGeneric__Ljava_lang_Object_2") public func Java_com_example_swift_SwiftModule__00024takeGeneric__Ljava_lang_Object_2(environment: UnsafeMutablePointer!, thisClass: jclass, s: jobject?) { - let sswiftObject$: (SomeProtocol) + let sswiftObject$: (any SomeProtocol) if environment.interface.IsInstanceOf(environment, s, _JNIMethodIDCache.JNISwiftInstance.class) != 0 { ... sswiftObject$ = spointer$Existential$ @@ -267,7 +267,7 @@ struct JNIProtocolTests { """ @_cdecl("Java_com_example_swift_SwiftModule__00024takeComposite__Ljava_lang_Object_2") public func Java_com_example_swift_SwiftModule__00024takeComposite__Ljava_lang_Object_2(environment: UnsafeMutablePointer!, thisClass: jclass, x: jobject?) { - let xswiftObject$: (SomeProtocol & B) + let xswiftObject$: (any (SomeProtocol & B)) if environment.interface.IsInstanceOf(environment, x, _JNIMethodIDCache.JNISwiftInstance.class) != 0 { let xpointer$ = environment.interface.CallLongMethodA(environment, x, _JNIMethodIDCache.JNISwiftInstance.memoryAddress, []) let xtypeMetadata$ = environment.interface.CallLongMethodA(environment, x, _JNIMethodIDCache.JNISwiftInstance.typeMetadataAddress, []) @@ -279,10 +279,10 @@ struct JNIProtocolTests { fatalError("xpointer$ memory address was null") } #if hasFeature(ImplicitOpenExistentials) - let xpointer$Existential$ = xpointer$RawPointer$.load(as: xpointer$DynamicType$) as! any (SomeProtocol & B) + let xpointer$Existential$ = xpointer$RawPointer$.load(as: xpointer$DynamicType$) as! (any (SomeProtocol & B)) #else - func xpointer$DoLoad(_ ty: Ty.Type) -> any (SomeProtocol & B) { - xpointer$RawPointer$.load(as: ty) as! any (SomeProtocol & B) + func xpointer$DoLoad(_ ty: Ty.Type) -> (any (SomeProtocol & B)) { + xpointer$RawPointer$.load(as: ty) as! (any (SomeProtocol & B)) } let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) #endif diff --git a/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift b/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift index 1a92fa994..67efc4312 100644 --- a/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNITupleTests.swift @@ -32,11 +32,11 @@ struct JNITupleTests { .java, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2 returnPair() { + public static org.swift.swiftkit.core.tuple.Tuple2 returnPair() { long[] result_0$ = new long[1]; java.lang.String[] result_1$ = new java.lang.String[1]; SwiftModule.$returnPair(result_0$, result_1$); - return new org.swift.swiftkit.core.tuple.Tuple2<>(result_0$[0], result_1$[0]); + return new org.swift.swiftkit.core.tuple.Tuple2(result_0$[0], result_1$[0]); } """, """ @@ -74,7 +74,7 @@ struct JNITupleTests { detectChunkByInitialLines: 2, expectedChunks: [ """ - public static void takePair(org.swift.swiftkit.core.tuple.Tuple2 arg) { + public static void takePair(org.swift.swiftkit.core.tuple.Tuple2 arg) { SwiftModule.$takePair(arg.$0, arg.$1); } """, @@ -100,24 +100,36 @@ struct JNITupleTests { ) } - @Test - func labeledTuple_javaBindings() throws { + @Test("Labelled tuple return (JNI)") + func labeledTuple_javaBindings_jni() throws { try assertOutput( input: source, .jni, .java, expectedChunks: [ """ - public static org.swift.swiftkit.core.tuple.Tuple2 labeledTuple() { + public static LabeledTuple_labeledTuple_x_y labeledTuple() { """, """ private static native void $labeledTuple(int[] result_0$, int[] result_1$); """, + """ + public static final class LabeledTuple_labeledTuple_x_y extends org.swift.swiftkit.core.tuple.Tuple2 { + """, + """ + public LabeledTuple_labeledTuple_x_y(T0 param0, T1 param1) { super(param0, param1); } + """, + """ + public T0 x() { return $0; } + """, + """ + public T1 y() { return $1; } + """, ] ) } - @Test + @Test("Labelled tuple return, Swift thunks (JNI)") func labeledTuple_swiftThunks() throws { try assertOutput( input: source,