From 9aaa4ba4a42f758f2f075e0978bb3652a8872679 Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:41:01 +0900 Subject: [PATCH 1/7] Use #require instead of forced unwrapping --- .../MethodImportTests.swift | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Tests/JExtractSwiftTests/MethodImportTests.swift b/Tests/JExtractSwiftTests/MethodImportTests.swift index aa546f3d..4f163c67 100644 --- a/Tests/JExtractSwiftTests/MethodImportTests.swift +++ b/Tests/JExtractSwiftTests/MethodImportTests.swift @@ -83,7 +83,7 @@ final class MethodImportTests { javaOutputDirectory: "/fake" ) - let funcDecl = st.importedGlobalFuncs.first { $0.name == "helloWorld" }! + let funcDecl = try #require(st.importedGlobalFuncs.first { $0.name == "helloWorld" }) let output = CodePrinter.toString { printer in generator.printJavaBindingWrapperMethod(&printer, funcDecl) @@ -117,9 +117,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = st.importedGlobalFuncs.first { + let funcDecl = try #require(st.importedGlobalFuncs.first { $0.name == "globalTakeInt" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -164,9 +164,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = st.importedGlobalFuncs.first { + let funcDecl = try #require(st.importedGlobalFuncs.first { $0.name == "globalTakeIntLongString" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -208,9 +208,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = st.importedGlobalFuncs.first { + let funcDecl = try #require(st.importedGlobalFuncs.first { $0.name == "globalReturnClass" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -252,9 +252,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = st.importedGlobalFuncs.first { + let funcDecl = try #require(st.importedGlobalFuncs.first { $0.name == "swapRawBufferPointer" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -299,9 +299,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl: ImportedFunc = st.importedTypes["MySwiftClass"]!.methods.first { + let funcDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.methods.first { $0.name == "helloMemberFunction" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -342,9 +342,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl: ImportedFunc = st.importedTypes["MySwiftClass"]!.methods.first { + let funcDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.methods.first { $0.name == "makeInt" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -391,9 +391,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let initDecl: ImportedFunc = st.importedTypes["MySwiftClass"]!.initializers.first { + let initDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.initializers.first { $0.name == "init" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, @@ -444,9 +444,9 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let initDecl: ImportedFunc = st.importedTypes["MySwiftStruct"]!.initializers.first { + let initDecl: ImportedFunc = try #require(st.importedTypes["MySwiftStruct"]!.initializers.first { $0.name == "init" - }! + }) let generator = FFMSwift2JavaGenerator( config: config, From 52e3c14805a6306695bfa4ce027f76e0fe5bf69a Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:41:52 +0900 Subject: [PATCH 2/7] effectiveWriteEmptyFiles --- Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift | 2 +- Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift | 2 +- Sources/SwiftJavaConfigurationShared/Configuration.swift | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index 41c06304..64614318 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -85,7 +85,7 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator { // If we are forced to write empty files, construct the expected outputs. // It is sufficient to use file names only, since SwiftPM requires names to be unique within a module anyway. - if translator.config.writeEmptyFiles ?? false { + if translator.config.effectiveWriteEmptyFiles { self.expectedOutputSwiftFileNames = Set( translator.inputs.compactMap { (input) -> String? in guard let fileName = input.path.split(separator: PATH_SEPARATOR).last else { diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift index 07b72487..beffe9fb 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift @@ -88,7 +88,7 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator { // If we are forced to write empty files, construct the expected outputs. // It is sufficient to use file names only, since SwiftPM requires names to be unique within a module anyway. - if translator.config.writeEmptyFiles ?? false { + if translator.config.effectiveWriteEmptyFiles { self.expectedOutputSwiftFileNames = Set( translator.inputs.compactMap { (input) -> String? in guard let fileName = input.path.split(separator: PATH_SEPARATOR).last else { diff --git a/Sources/SwiftJavaConfigurationShared/Configuration.swift b/Sources/SwiftJavaConfigurationShared/Configuration.swift index 7eab2fef..ea5981f2 100644 --- a/Sources/SwiftJavaConfigurationShared/Configuration.swift +++ b/Sources/SwiftJavaConfigurationShared/Configuration.swift @@ -49,7 +49,10 @@ public struct Configuration: Codable { mode ?? .default } - public var writeEmptyFiles: Bool? // FIXME: default it to false, but that plays not nice with Codable + public var writeEmptyFiles: Bool? + public var effectiveWriteEmptyFiles: Bool { + writeEmptyFiles ?? false + } public var minimumInputAccessLevelMode: JExtractMinimumAccessLevelMode? public var effectiveMinimumInputAccessLevelMode: JExtractMinimumAccessLevelMode { From 73f1f68f27ccd680d1f21d7528c802e2ce07a10a Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:45:32 +0900 Subject: [PATCH 3/7] Remove #if hasFeature(ImplicitOpenExistentials) block --- .../JNISwift2JavaGenerator+NativeTranslation.swift | 8 -------- .../JExtractSwiftTests/JNI/JNIProtocolTests.swift | 14 -------------- 2 files changed, 22 deletions(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index 2351ea47..a0c829eb 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -1319,7 +1319,6 @@ extension JNISwift2JavaGenerator { let existentialType = SwiftKitPrinting.renderExistentialType(protocolTypes) - // TODO: Remove the _openExistential when we decide to only support language mode v6+ printer.print( """ guard let \(inner)TypeMetadataPointer$ = UnsafeRawPointer(bitPattern: Int(Int64(fromJNI: \(typeMetadataVariableName), in: environment))) else { @@ -1329,14 +1328,7 @@ extension JNISwift2JavaGenerator { guard let \(inner)RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: \(inner), in: environment))) else { fatalError("\(inner) memory address was null") } - #if hasFeature(ImplicitOpenExistentials) let \(existentialName) = \(inner)RawPointer$.load(as: \(inner)DynamicType$) as! \(existentialType) - #else - func \(inner)DoLoad(_ ty: Ty.Type) -> \(existentialType) { - \(inner)RawPointer$.load(as: ty) as! \(existentialType) - } - let \(existentialName) = _openExistential(\(inner)DynamicType$, do: \(inner)DoLoad) - #endif """ ) return existentialName diff --git a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift index 6e763172..f7c073f8 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift @@ -140,14 +140,7 @@ struct JNIProtocolTests { guard let xpointer$RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: xpointer$, in: environment))) else { fatalError("xpointer$ memory address was null") } - #if hasFeature(ImplicitOpenExistentials) 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) - } - let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) - #endif xswiftObject$ = xpointer$Existential$ } else { @@ -278,14 +271,7 @@ struct JNIProtocolTests { guard let xpointer$RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: xpointer$, in: environment))) else { fatalError("xpointer$ memory address was null") } - #if hasFeature(ImplicitOpenExistentials) 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)) - } - let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) - #endif xswiftObject$ = xpointer$Existential$ } else { From 17465e899d0a5733c7bc369203cf74bae18e8bd5 Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:46:08 +0900 Subject: [PATCH 4/7] Remove unused variable --- .../JNI/JNISwift2JavaGenerator+JavaTranslation.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index ddb88b9f..53db4d40 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -1162,7 +1162,6 @@ extension JNISwift2JavaGenerator { genericParameters: [SwiftGenericParameterDeclaration], genericRequirements: [SwiftGenericRequirement], ) throws -> TranslatedResult { - let arity = elements.count var outParameters: [OutParameter] = [] var elementOutParamNames: [String] = [] var elementConversions: [JavaNativeConversionStep] = [] From 9d9fb0b76d7e13ae6058869699e4e739b09458bf Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:53:17 +0900 Subject: [PATCH 5/7] Suppress warnings --- Tests/JExtractSwiftTests/FFMNestedTypesTests.swift | 8 ++------ .../SwiftJavaConfigurationTests.swift | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Tests/JExtractSwiftTests/FFMNestedTypesTests.swift b/Tests/JExtractSwiftTests/FFMNestedTypesTests.swift index 4c5171c5..1b23d299 100644 --- a/Tests/JExtractSwiftTests/FFMNestedTypesTests.swift +++ b/Tests/JExtractSwiftTests/FFMNestedTypesTests.swift @@ -37,7 +37,7 @@ final class FFMNestedTypesTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let generator = FFMSwift2JavaGenerator( + let _ = FFMSwift2JavaGenerator( config: config, translator: st, javaPackage: "com.example.swift", @@ -45,10 +45,6 @@ final class FFMNestedTypesTests { javaOutputDirectory: "/fake" ) - guard let ty = st.importedTypes["MyNamespace.MyNestedStruct"] else { - fatalError("Didn't import nested type!") - } - + #expect(st.importedTypes["MyNamespace.MyNestedStruct"] != nil, "Didn't import nested type!") } - } diff --git a/Tests/SwiftJavaConfigurationSharedTests/SwiftJavaConfigurationTests.swift b/Tests/SwiftJavaConfigurationSharedTests/SwiftJavaConfigurationTests.swift index 4dbea421..eb8c2dd4 100644 --- a/Tests/SwiftJavaConfigurationSharedTests/SwiftJavaConfigurationTests.swift +++ b/Tests/SwiftJavaConfigurationSharedTests/SwiftJavaConfigurationTests.swift @@ -20,7 +20,7 @@ struct SwiftJavaConfigurationTests { @Test func parseJSONWithComments() throws { - let config = try readConfiguration( + let _ = try readConfiguration( string: """ // some comments From 0df506072684b818d896002897dd22cdc0134779 Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 15:54:18 +0900 Subject: [PATCH 6/7] swift format --- .../MethodImportTests.swift | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/Tests/JExtractSwiftTests/MethodImportTests.swift b/Tests/JExtractSwiftTests/MethodImportTests.swift index 4f163c67..9d723c3f 100644 --- a/Tests/JExtractSwiftTests/MethodImportTests.swift +++ b/Tests/JExtractSwiftTests/MethodImportTests.swift @@ -117,9 +117,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = try #require(st.importedGlobalFuncs.first { - $0.name == "globalTakeInt" - }) + let funcDecl = try #require( + st.importedGlobalFuncs.first { + $0.name == "globalTakeInt" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -164,9 +166,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = try #require(st.importedGlobalFuncs.first { - $0.name == "globalTakeIntLongString" - }) + let funcDecl = try #require( + st.importedGlobalFuncs.first { + $0.name == "globalTakeIntLongString" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -208,9 +212,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = try #require(st.importedGlobalFuncs.first { - $0.name == "globalReturnClass" - }) + let funcDecl = try #require( + st.importedGlobalFuncs.first { + $0.name == "globalReturnClass" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -252,9 +258,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl = try #require(st.importedGlobalFuncs.first { - $0.name == "swapRawBufferPointer" - }) + let funcDecl = try #require( + st.importedGlobalFuncs.first { + $0.name == "swapRawBufferPointer" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -299,9 +307,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.methods.first { - $0.name == "helloMemberFunction" - }) + let funcDecl: ImportedFunc = try #require( + st.importedTypes["MySwiftClass"]!.methods.first { + $0.name == "helloMemberFunction" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -342,9 +352,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let funcDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.methods.first { - $0.name == "makeInt" - }) + let funcDecl: ImportedFunc = try #require( + st.importedTypes["MySwiftClass"]!.methods.first { + $0.name == "makeInt" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -391,9 +403,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let initDecl: ImportedFunc = try #require(st.importedTypes["MySwiftClass"]!.initializers.first { - $0.name == "init" - }) + let initDecl: ImportedFunc = try #require( + st.importedTypes["MySwiftClass"]!.initializers.first { + $0.name == "init" + } + ) let generator = FFMSwift2JavaGenerator( config: config, @@ -444,9 +458,11 @@ final class MethodImportTests { try st.analyze(path: "Fake.swift", text: class_interfaceFile) - let initDecl: ImportedFunc = try #require(st.importedTypes["MySwiftStruct"]!.initializers.first { - $0.name == "init" - }) + let initDecl: ImportedFunc = try #require( + st.importedTypes["MySwiftStruct"]!.initializers.first { + $0.name == "init" + } + ) let generator = FFMSwift2JavaGenerator( config: config, From 1f6c402096408030786ae184b3dd0a2a513228e7 Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2026 16:17:17 +0900 Subject: [PATCH 7/7] Revert "Remove #if hasFeature(ImplicitOpenExistentials) block" This reverts commit 73f1f68f27ccd680d1f21d7528c802e2ce07a10a. --- .../JNISwift2JavaGenerator+NativeTranslation.swift | 8 ++++++++ .../JExtractSwiftTests/JNI/JNIProtocolTests.swift | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index a0c829eb..2351ea47 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -1319,6 +1319,7 @@ extension JNISwift2JavaGenerator { let existentialType = SwiftKitPrinting.renderExistentialType(protocolTypes) + // TODO: Remove the _openExistential when we decide to only support language mode v6+ printer.print( """ guard let \(inner)TypeMetadataPointer$ = UnsafeRawPointer(bitPattern: Int(Int64(fromJNI: \(typeMetadataVariableName), in: environment))) else { @@ -1328,7 +1329,14 @@ extension JNISwift2JavaGenerator { guard let \(inner)RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: \(inner), in: environment))) else { fatalError("\(inner) memory address was null") } + #if hasFeature(ImplicitOpenExistentials) let \(existentialName) = \(inner)RawPointer$.load(as: \(inner)DynamicType$) as! \(existentialType) + #else + func \(inner)DoLoad(_ ty: Ty.Type) -> \(existentialType) { + \(inner)RawPointer$.load(as: ty) as! \(existentialType) + } + let \(existentialName) = _openExistential(\(inner)DynamicType$, do: \(inner)DoLoad) + #endif """ ) return existentialName diff --git a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift index f7c073f8..6e763172 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift @@ -140,7 +140,14 @@ struct JNIProtocolTests { guard let xpointer$RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: xpointer$, in: environment))) else { fatalError("xpointer$ memory address was null") } + #if hasFeature(ImplicitOpenExistentials) 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) + } + let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) + #endif xswiftObject$ = xpointer$Existential$ } else { @@ -271,7 +278,14 @@ struct JNIProtocolTests { guard let xpointer$RawPointer$ = UnsafeMutableRawPointer(bitPattern: Int(Int64(fromJNI: xpointer$, in: environment))) else { fatalError("xpointer$ memory address was null") } + #if hasFeature(ImplicitOpenExistentials) 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)) + } + let xpointer$Existential$ = _openExistential(xpointer$DynamicType$, do: xpointer$DoLoad) + #endif xswiftObject$ = xpointer$Existential$ } else {