From 433ae800c6ac8ae1e17929b446ced62ba2e053e1 Mon Sep 17 00:00:00 2001 From: clemo97 Date: Mon, 26 Jan 2026 19:43:23 +0300 Subject: [PATCH 1/5] Append parameter labels to Java method names for overload disambiguation --- .../com/example/swift/HelloJava2Swift.java | 28 +++++++++---------- ...MSwift2JavaGenerator+JavaTranslation.swift | 15 +++++++++- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index a13125478..9bcecb3ff 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -40,13 +40,13 @@ public static void main(String[] args) { static void examples() { MySwiftLibrary.helloWorld(); - MySwiftLibrary.globalTakeInt(1337); + MySwiftLibrary.globalTakeInt_i(1337); - long cnt = MySwiftLibrary.globalWriteString("String from Java"); + long cnt = MySwiftLibrary.globalWriteString_string("String from Java"); CallTraces.trace("count = " + cnt); - MySwiftLibrary.globalCallMeRunnable(() -> { + MySwiftLibrary.globalCallMeRunnable_run(() -> { CallTraces.trace("running runnable"); }); @@ -55,7 +55,7 @@ static void examples() { // Example of using an arena; MyClass.deinit is run at end of scope try (var arena = AllocatingSwiftArena.ofConfined()) { - MySwiftClass obj = MySwiftClass.init(2222, 7777, arena); + MySwiftClass obj = MySwiftClass.init_len_cap(2222, 7777, arena); // just checking retains/releases work CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj)); @@ -68,14 +68,14 @@ static void examples() { CallTraces.trace("obj.counter = " + obj.getCounter()); obj.voidMethod(); - obj.takeIntMethod(42); + obj.takeIntMethod_i(42); - MySwiftClass otherObj = MySwiftClass.factory(12, 42, arena); + MySwiftClass otherObj = MySwiftClass.factory_len_cap(12, 42, arena); otherObj.voidMethod(); - MySwiftStruct swiftValue = MySwiftStruct.init(2222, 1111, arena); + MySwiftStruct swiftValue = MySwiftStruct.init_cap_len(2222, 1111, arena); CallTraces.trace("swiftValue.capacity = " + swiftValue.getCapacity()); - swiftValue.withCapLen((cap, len) -> { + swiftValue.withCapLen__((cap, len) -> { CallTraces.trace("withCapLenCallback: cap=" + cap + ", len=" + len); }); } @@ -83,11 +83,11 @@ static void examples() { // Example of using 'Data'. try (var arena = AllocatingSwiftArena.ofConfined()) { var origBytes = arena.allocateFrom("foobar"); - var origDat = Data.init(origBytes, origBytes.byteSize(), arena); + var origDat = Data.init_bytes_count(origBytes, origBytes.byteSize(), arena); CallTraces.trace("origDat.count = " + origDat.getCount()); - var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena); - retDat.withUnsafeBytes((retBytes) -> { + var retDat = MySwiftLibrary.globalReceiveReturnData_data(origDat, arena); + retDat.withUnsafeBytes__((retBytes) -> { var str = retBytes.getString(0); CallTraces.trace("retStr=" + str); }); @@ -95,9 +95,9 @@ static void examples() { try (var arena = AllocatingSwiftArena.ofConfined()) { var bytes = arena.allocateFrom("hello"); - var dat = Data.init(bytes, bytes.byteSize(), arena); - MySwiftLibrary.globalReceiveSomeDataProtocol(dat); - MySwiftLibrary.globalReceiveOptional(OptionalLong.of(12), Optional.of(dat)); + var dat = Data.init_bytes_count(bytes, bytes.byteSize(), arena); + MySwiftLibrary.globalReceiveSomeDataProtocol_data(dat); + MySwiftLibrary.globalReceiveOptional_o1_o2(OptionalLong.of(12), Optional.of(dat)); } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index da1914d45..8eaef5f8a 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -156,11 +156,24 @@ extension FFMSwift2JavaGenerator { let loweredSignature = try lowering.lowerFunctionSignature(decl.functionSignature) // Name. - let javaName = switch decl.apiKind { + let baseName = switch decl.apiKind { case .getter, .subscriptGetter: decl.javaGetterName case .setter, .subscriptSetter: decl.javaSetterName case .function, .initializer, .enumCase: decl.name } + + // Add parameter labels to make method names unique (for overloading support) + let suffix: String + switch decl.apiKind { + case .getter, .subscriptGetter, .setter, .subscriptSetter: + suffix = "" + default: + suffix = decl.functionSignature.parameters + .map { "_" + ($0.argumentLabel ?? "_") } + .joined() + } + + let javaName = baseName + suffix // Signature. let translatedSignature = try translate(loweredFunctionSignature: loweredSignature, methodName: javaName) From cc77cc5a88d2f1ccd5c385146b66c231593358b8 Mon Sep 17 00:00:00 2001 From: clemo97 Date: Mon, 2 Mar 2026 22:55:52 +0300 Subject: [PATCH 2/5] Fix Swift overloads producing uncompilable Java wrappers - Add DuplicateNames struct for two-pass conflict detection - Only apply parameter label suffixes when base names conflict - Extract makeJavaMethodName and makeMethodNameWithParamsSuffix helpers - Fix FoundationData.fromByteArray to use generated init__ name - Add globalMethodOverloadingInt overload test methods to sample - Add OverloadSample.swift demonstrating conflict/non-conflict cases --- .../MySwiftLibrary/MySwiftLibrary.swift | 10 ++ .../MySwiftLibrary/OverloadSample.swift | 38 ++++++++ .../com/example/swift/HelloJava2Swift.java | 28 +++--- ...FMSwift2JavaGenerator+FoundationData.swift | 2 +- ...MSwift2JavaGenerator+JavaTranslation.swift | 91 +++++++++++++------ ...ift2JavaGenerator+SwiftThunkPrinting.swift | 3 + .../FFM/FFMSwift2JavaGenerator.swift | 5 + 7 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/OverloadSample.swift diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index b8b19d902..a2bbcb834 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -108,6 +108,16 @@ func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: Stri fflush(stdout) } +// ==== Overload test methods (same base name, different parameter labels → conflict → suffix needed) + +public func globalMethodOverloadingInt(a: Int) { + p("globalMethodOverloadingInt(a: \(a))") +} + +public func globalMethodOverloadingInt(b: Int) { + p("globalMethodOverloadingInt(b: \(b))") +} + #if os(Linux) // FIXME: why do we need this workaround? @_silgen_name("_objc_autoreleaseReturnValue") diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/OverloadSample.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/OverloadSample.swift new file mode 100644 index 000000000..337847d3d --- /dev/null +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/OverloadSample.swift @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +public class OverloadSample { + public func takeValue(a: String) {} + public func takeValue(b: String) {} +} + +public class OverloadSample2 { + public func takeArgument(a: String) { + print("Got: \(a)") + } + + public func takeArgument(b: String) { + print("Got: \(b)") + } +} + +public class OverloadSample3 { + public func takeChair(a: String) { + print("Got: \(a)") + } + + public func takeTable(b: String) { + print("Got: \(b)") + } +} diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index 9bcecb3ff..6b835a05a 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -40,13 +40,13 @@ public static void main(String[] args) { static void examples() { MySwiftLibrary.helloWorld(); - MySwiftLibrary.globalTakeInt_i(1337); + MySwiftLibrary.globalTakeInt(1337); - long cnt = MySwiftLibrary.globalWriteString_string("String from Java"); + long cnt = MySwiftLibrary.globalWriteString("String from Java"); CallTraces.trace("count = " + cnt); - MySwiftLibrary.globalCallMeRunnable_run(() -> { + MySwiftLibrary.globalCallMeRunnable(() -> { CallTraces.trace("running runnable"); }); @@ -55,7 +55,7 @@ static void examples() { // Example of using an arena; MyClass.deinit is run at end of scope try (var arena = AllocatingSwiftArena.ofConfined()) { - MySwiftClass obj = MySwiftClass.init_len_cap(2222, 7777, arena); + MySwiftClass obj = MySwiftClass.init(2222, 7777, arena); // just checking retains/releases work CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj)); @@ -68,14 +68,14 @@ static void examples() { CallTraces.trace("obj.counter = " + obj.getCounter()); obj.voidMethod(); - obj.takeIntMethod_i(42); + obj.takeIntMethod(42); - MySwiftClass otherObj = MySwiftClass.factory_len_cap(12, 42, arena); + MySwiftClass otherObj = MySwiftClass.factory(12, 42, arena); otherObj.voidMethod(); - MySwiftStruct swiftValue = MySwiftStruct.init_cap_len(2222, 1111, arena); + MySwiftStruct swiftValue = MySwiftStruct.init(2222, 1111, arena); CallTraces.trace("swiftValue.capacity = " + swiftValue.getCapacity()); - swiftValue.withCapLen__((cap, len) -> { + swiftValue.withCapLen((cap, len) -> { CallTraces.trace("withCapLenCallback: cap=" + cap + ", len=" + len); }); } @@ -86,8 +86,8 @@ static void examples() { var origDat = Data.init_bytes_count(origBytes, origBytes.byteSize(), arena); CallTraces.trace("origDat.count = " + origDat.getCount()); - var retDat = MySwiftLibrary.globalReceiveReturnData_data(origDat, arena); - retDat.withUnsafeBytes__((retBytes) -> { + var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena); + retDat.withUnsafeBytes((retBytes) -> { var str = retBytes.getString(0); CallTraces.trace("retStr=" + str); }); @@ -96,10 +96,14 @@ static void examples() { try (var arena = AllocatingSwiftArena.ofConfined()) { var bytes = arena.allocateFrom("hello"); var dat = Data.init_bytes_count(bytes, bytes.byteSize(), arena); - MySwiftLibrary.globalReceiveSomeDataProtocol_data(dat); - MySwiftLibrary.globalReceiveOptional_o1_o2(OptionalLong.of(12), Optional.of(dat)); + MySwiftLibrary.globalReceiveSomeDataProtocol(dat); + MySwiftLibrary.globalReceiveOptional(OptionalLong.of(12), Optional.of(dat)); } + // Test overload conflict detection: only conflicting methods get suffixes + MySwiftLibrary.globalMethodOverloadingInt_a(100); + MySwiftLibrary.globalMethodOverloadingInt_b(200); + CallTraces.trace("Overload conflict detection test passed!"); System.out.println("DONE."); } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift index b3fa1b30b..136f3bc68 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift @@ -40,7 +40,7 @@ extension FFMSwift2JavaGenerator { */ public static \(typeName) fromByteArray(byte[] bytes, AllocatingSwiftArena arena) { Objects.requireNonNull(bytes, "bytes cannot be null"); - return \(typeName).init(bytes, arena); + return \(typeName).init__(bytes, arena); } """ ) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index 61f9bad24..50f4d1227 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -27,7 +27,8 @@ extension FFMSwift2JavaGenerator { do { let translation = JavaTranslation( config: self.config, - knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable), + dupeNames: self.currentDupeNames ) translated = try translation.translate(decl) } catch { @@ -39,6 +40,37 @@ extension FFMSwift2JavaGenerator { return translated } + /// Encapsulates detection and storage of Swift method base names that would produce + /// duplicate Java method signatures due to parameter-label overloading. + /// + /// Swift allows overloads via parameter labels (e.g., `takeValue(a:)` and `takeValue(b:)`), + /// but Java only distinguishes methods by their parameter types. This type identifies + /// which base names have actual Java naming conflicts so suffixes are applied selectively. + struct DuplicateNames { + private var duplicates: Set = [] + + /// Detects which base names among `methods` would clash in Java. + init(for methods: [ImportedFunc]) { + var seen: Set = [] + for method in methods { + let baseName = + switch method.apiKind { + case .getter, .subscriptGetter: method.javaGetterName + case .setter, .subscriptSetter: method.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: method.name + } + if !seen.insert(baseName).inserted { + duplicates.insert(baseName) + } + } + } + + /// Returns whether the given base name has a Java naming conflict and needs a parameter label suffix. + func needsSuffix(for baseName: String) -> Bool { + duplicates.contains(baseName) + } + } + /// Represent a Swift API parameter translated to Java. struct TranslatedParameter { /// Java parameter(s) mapped to the Swift parameter. @@ -145,10 +177,12 @@ extension FFMSwift2JavaGenerator { struct JavaTranslation { let config: Configuration var knownTypes: SwiftKnownTypes + var dupeNames: DuplicateNames - init(config: Configuration, knownTypes: SwiftKnownTypes) { + init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(for: [])) { self.config = config self.knownTypes = knownTypes + self.dupeNames = dupeNames } func translate(_ decl: ImportedFunc) throws -> TranslatedFunctionDecl { @@ -156,30 +190,7 @@ extension FFMSwift2JavaGenerator { let loweredSignature = try lowering.lowerFunctionSignature(decl.functionSignature) // Name. - let baseName = switch decl.apiKind { - case .getter, .subscriptGetter: decl.javaGetterName - case .setter, .subscriptSetter: decl.javaSetterName - case .function, .initializer, .enumCase: decl.name - } - - // Add parameter labels to make method names unique (for overloading support) - let suffix: String - switch decl.apiKind { - case .getter, .subscriptGetter, .setter, .subscriptSetter: - suffix = "" - default: - suffix = decl.functionSignature.parameters - .map { "_" + ($0.argumentLabel ?? "_") } - .joined() - } - - let javaName = baseName + suffix - let javaName = - switch decl.apiKind { - case .getter, .subscriptGetter: decl.javaGetterName - case .setter, .subscriptSetter: decl.javaSetterName - case .function, .synthesizedFunction, .initializer, .enumCase: decl.name - } + let javaName = makeJavaMethodName(decl) // Signature. let translatedSignature = try translate(loweredFunctionSignature: loweredSignature, methodName: javaName) @@ -211,6 +222,34 @@ extension FFMSwift2JavaGenerator { ) } + /// Returns the Java method name for the given Swift declaration, applying parameter + /// label suffixes only when a naming conflict with another method would occur. + private func makeJavaMethodName(_ decl: ImportedFunc) -> String { + let baseName = switch decl.apiKind { + case .getter, .subscriptGetter: decl.javaGetterName + case .setter, .subscriptSetter: decl.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name + } + return baseName + makeMethodNameWithParamsSuffix(decl, baseName: baseName) + } + + /// Returns the parameter label suffix for a method name if needed, or an empty string. + /// + /// Suffixes are only applied when the method's base name has a Java naming conflict + /// (i.e., another Swift overload would produce the same Java method name). + /// Getters and setters never receive suffixes. + private func makeMethodNameWithParamsSuffix(_ decl: ImportedFunc, baseName: String) -> String { + switch decl.apiKind { + case .getter, .subscriptGetter, .setter, .subscriptSetter: + return "" + default: + guard dupeNames.needsSuffix(for: baseName) else { return "" } + return decl.functionSignature.parameters + .map { "_" + ($0.argumentLabel ?? "_") } + .joined() + } + } + /// Translate Swift closure type to Java functional interface. func translateFunctionType( name: String, diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index 9dbc38321..0f1ea6234 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -122,6 +122,7 @@ extension FFMSwift2JavaGenerator { self.lookupContext.symbolTable.printImportedModules(&printer) + self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) for thunk in stt.renderGlobalThunks() { printer.print(thunk) printer.println() @@ -140,6 +141,8 @@ extension FFMSwift2JavaGenerator { package func printSwiftThunkSources(_ printer: inout CodePrinter, ty: ImportedNominalType) throws { let stt = SwiftThunkTranslator(self) + self.currentDupeNames = DuplicateNames(for: ty.initializers + ty.variables + ty.methods) + printer.print( """ // Generated by swift-java diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index ffc317fee..d5b20ed32 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -38,6 +38,9 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator { /// Cached Java translation result. 'nil' indicates failed translation. var translatedDecls: [ImportedFunc: TranslatedFunctionDecl?] = [:] + /// The set of method base names that have Java naming conflicts for the current type/module being generated. + var currentDupeNames: DuplicateNames = DuplicateNames(for: []) + /// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet, /// and write an empty file for those. /// @@ -169,6 +172,7 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) + self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) printModuleClass(&printer) { printer in for decl in analysis.importedGlobalVariables { @@ -188,6 +192,7 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) // TODO: we could have some imports be driven from types used in the generated decl + self.currentDupeNames = DuplicateNames(for: decl.initializers + decl.variables + decl.methods) printNominal(&printer, decl) { printer in // We use a static field to abuse the initialization order such that by the time we get type metadata, // we already have loaded the library where it will be obtained from. From 4edbd07579ebd7c49ccdcc917a7fe262fdfa10f3 Mon Sep 17 00:00:00 2001 From: clemo97 Date: Mon, 9 Mar 2026 18:14:20 +0300 Subject: [PATCH 3/5] jextract/ffm: Fix duplicate detection to check Java method signatures Changed DuplicateNames conflict detection to check actual Java method signatures (name + parameter types) instead of just Swift base names. Previously, methods with the same Swift base name but different Java parameter types (e.g., Data.init(MemorySegment, long) and Data.init(byte[])) were incorrectly marked as duplicates and given parameter label suffixes. Now only methods that would produce identical Java signatures are marked as duplicates, fixing DataImportTests failures. Fixes #544 --- ...MSwift2JavaGenerator+JavaTranslation.swift | 71 +++++++++++++++---- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 12 +++- .../FFM/FFMSwift2JavaGenerator.swift | 14 +++- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index 50f4d1227..0fbc84a14 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -50,21 +50,61 @@ extension FFMSwift2JavaGenerator { private var duplicates: Set = [] /// Detects which base names among `methods` would clash in Java. - init(for methods: [ImportedFunc]) { - var seen: Set = [] + /// Only considers methods that can actually be translated to Java AND checks + /// for actual Java signature conflicts (not just Swift base name collisions). + init(for methods: [ImportedFunc], config: Configuration, lookupContext: SwiftTypeLookupContext) { + // First pass: Build Java method signatures for translatable methods + var javaSignatures: [String: [String]] = [:] // baseName -> [full Java signatures] + for method in methods { - let baseName = - switch method.apiKind { - case .getter, .subscriptGetter: method.javaGetterName - case .setter, .subscriptSetter: method.javaSetterName - case .function, .synthesizedFunction, .initializer, .enumCase: method.name + do { + // Attempt translation without checking for duplicates (bootstrap phase) + let translation = JavaTranslation( + config: config, + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable), + dupeNames: DuplicateNames(_bootstrap: []) + ) + let translated = try translation.translate(method) + + // Build Java method signature (name + parameter types) + let baseName = translated.name + let paramTypes = translated.translatedSignature.parameters + .flatMap { $0.javaParameters } + .map { $0.type.description } + .joined(separator: ",") + let javaSignature = "\(baseName)(\(paramTypes))" + + javaSignatures[baseName, default: []].append(javaSignature) + } catch { + // Method can't be translated, skip it + continue + } + } + + // Second pass: Detect base names that have actual Java signature conflicts + var seen: Set = [] + for (baseName, signatures) in javaSignatures { + // Multiple methods with same base name, check if Java signatures actually conflict + if signatures.count > 1 { + // Check if any two signatures are identical + var signatureSet: Set = [] + for sig in signatures { + if !signatureSet.insert(sig).inserted { + // Found duplicate Java signature! + duplicates.insert(baseName) + break + } } - if !seen.insert(baseName).inserted { - duplicates.insert(baseName) } } } + /// Internal initializer for bootstrap phase (when we don't want to check duplicates) + init(_bootstrap methods: [ImportedFunc]) { + // Empty initialization - no duplicates detected + self.duplicates = [] + } + /// Returns whether the given base name has a Java naming conflict and needs a parameter label suffix. func needsSuffix(for baseName: String) -> Bool { duplicates.contains(baseName) @@ -179,7 +219,7 @@ extension FFMSwift2JavaGenerator { var knownTypes: SwiftKnownTypes var dupeNames: DuplicateNames - init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(for: [])) { + init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(_bootstrap: [])) { self.config = config self.knownTypes = knownTypes self.dupeNames = dupeNames @@ -225,11 +265,12 @@ extension FFMSwift2JavaGenerator { /// Returns the Java method name for the given Swift declaration, applying parameter /// label suffixes only when a naming conflict with another method would occur. private func makeJavaMethodName(_ decl: ImportedFunc) -> String { - let baseName = switch decl.apiKind { - case .getter, .subscriptGetter: decl.javaGetterName - case .setter, .subscriptSetter: decl.javaSetterName - case .function, .synthesizedFunction, .initializer, .enumCase: decl.name - } + let baseName = + switch decl.apiKind { + case .getter, .subscriptGetter: decl.javaGetterName + case .setter, .subscriptSetter: decl.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name + } return baseName + makeMethodNameWithParamsSuffix(decl, baseName: baseName) } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index 0f1ea6234..16081471b 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -122,7 +122,11 @@ extension FFMSwift2JavaGenerator { self.lookupContext.symbolTable.printImportedModules(&printer) - self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) + self.currentDupeNames = DuplicateNames( + for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, + config: self.config, + lookupContext: self.lookupContext + ) for thunk in stt.renderGlobalThunks() { printer.print(thunk) printer.println() @@ -141,7 +145,11 @@ extension FFMSwift2JavaGenerator { package func printSwiftThunkSources(_ printer: inout CodePrinter, ty: ImportedNominalType) throws { let stt = SwiftThunkTranslator(self) - self.currentDupeNames = DuplicateNames(for: ty.initializers + ty.variables + ty.methods) + self.currentDupeNames = DuplicateNames( + for: ty.initializers + ty.variables + ty.methods, + config: self.config, + lookupContext: self.lookupContext + ) printer.print( """ diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index d5b20ed32..1a877e769 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -39,7 +39,7 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator { var translatedDecls: [ImportedFunc: TranslatedFunctionDecl?] = [:] /// The set of method base names that have Java naming conflicts for the current type/module being generated. - var currentDupeNames: DuplicateNames = DuplicateNames(for: []) + var currentDupeNames: DuplicateNames = DuplicateNames(_bootstrap: []) /// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet, /// and write an empty file for those. @@ -172,7 +172,11 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) - self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) + self.currentDupeNames = DuplicateNames( + for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, + config: self.config, + lookupContext: self.lookupContext + ) printModuleClass(&printer) { printer in for decl in analysis.importedGlobalVariables { @@ -192,7 +196,11 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) // TODO: we could have some imports be driven from types used in the generated decl - self.currentDupeNames = DuplicateNames(for: decl.initializers + decl.variables + decl.methods) + self.currentDupeNames = DuplicateNames( + for: decl.initializers + decl.variables + decl.methods, + config: self.config, + lookupContext: self.lookupContext + ) printNominal(&printer, decl) { printer in // We use a static field to abuse the initialization order such that by the time we get type metadata, // we already have loaded the library where it will be obtained from. From cdd38fcf5ef5a3ae19b4272715c125b870b9eb9a Mon Sep 17 00:00:00 2001 From: clemo97 Date: Mon, 9 Mar 2026 18:24:52 +0300 Subject: [PATCH 4/5] Revert "jextract/ffm: Fix duplicate detection to check Java method signatures" This reverts commit 4edbd07579ebd7c49ccdcc917a7fe262fdfa10f3. --- ...MSwift2JavaGenerator+JavaTranslation.swift | 71 ++++--------------- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 12 +--- .../FFM/FFMSwift2JavaGenerator.swift | 14 +--- 3 files changed, 20 insertions(+), 77 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index 0fbc84a14..50f4d1227 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -50,61 +50,21 @@ extension FFMSwift2JavaGenerator { private var duplicates: Set = [] /// Detects which base names among `methods` would clash in Java. - /// Only considers methods that can actually be translated to Java AND checks - /// for actual Java signature conflicts (not just Swift base name collisions). - init(for methods: [ImportedFunc], config: Configuration, lookupContext: SwiftTypeLookupContext) { - // First pass: Build Java method signatures for translatable methods - var javaSignatures: [String: [String]] = [:] // baseName -> [full Java signatures] - - for method in methods { - do { - // Attempt translation without checking for duplicates (bootstrap phase) - let translation = JavaTranslation( - config: config, - knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable), - dupeNames: DuplicateNames(_bootstrap: []) - ) - let translated = try translation.translate(method) - - // Build Java method signature (name + parameter types) - let baseName = translated.name - let paramTypes = translated.translatedSignature.parameters - .flatMap { $0.javaParameters } - .map { $0.type.description } - .joined(separator: ",") - let javaSignature = "\(baseName)(\(paramTypes))" - - javaSignatures[baseName, default: []].append(javaSignature) - } catch { - // Method can't be translated, skip it - continue - } - } - - // Second pass: Detect base names that have actual Java signature conflicts + init(for methods: [ImportedFunc]) { var seen: Set = [] - for (baseName, signatures) in javaSignatures { - // Multiple methods with same base name, check if Java signatures actually conflict - if signatures.count > 1 { - // Check if any two signatures are identical - var signatureSet: Set = [] - for sig in signatures { - if !signatureSet.insert(sig).inserted { - // Found duplicate Java signature! - duplicates.insert(baseName) - break - } + for method in methods { + let baseName = + switch method.apiKind { + case .getter, .subscriptGetter: method.javaGetterName + case .setter, .subscriptSetter: method.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: method.name } + if !seen.insert(baseName).inserted { + duplicates.insert(baseName) } } } - /// Internal initializer for bootstrap phase (when we don't want to check duplicates) - init(_bootstrap methods: [ImportedFunc]) { - // Empty initialization - no duplicates detected - self.duplicates = [] - } - /// Returns whether the given base name has a Java naming conflict and needs a parameter label suffix. func needsSuffix(for baseName: String) -> Bool { duplicates.contains(baseName) @@ -219,7 +179,7 @@ extension FFMSwift2JavaGenerator { var knownTypes: SwiftKnownTypes var dupeNames: DuplicateNames - init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(_bootstrap: [])) { + init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(for: [])) { self.config = config self.knownTypes = knownTypes self.dupeNames = dupeNames @@ -265,12 +225,11 @@ extension FFMSwift2JavaGenerator { /// Returns the Java method name for the given Swift declaration, applying parameter /// label suffixes only when a naming conflict with another method would occur. private func makeJavaMethodName(_ decl: ImportedFunc) -> String { - let baseName = - switch decl.apiKind { - case .getter, .subscriptGetter: decl.javaGetterName - case .setter, .subscriptSetter: decl.javaSetterName - case .function, .synthesizedFunction, .initializer, .enumCase: decl.name - } + let baseName = switch decl.apiKind { + case .getter, .subscriptGetter: decl.javaGetterName + case .setter, .subscriptSetter: decl.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name + } return baseName + makeMethodNameWithParamsSuffix(decl, baseName: baseName) } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index 16081471b..0f1ea6234 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -122,11 +122,7 @@ extension FFMSwift2JavaGenerator { self.lookupContext.symbolTable.printImportedModules(&printer) - self.currentDupeNames = DuplicateNames( - for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, - config: self.config, - lookupContext: self.lookupContext - ) + self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) for thunk in stt.renderGlobalThunks() { printer.print(thunk) printer.println() @@ -145,11 +141,7 @@ extension FFMSwift2JavaGenerator { package func printSwiftThunkSources(_ printer: inout CodePrinter, ty: ImportedNominalType) throws { let stt = SwiftThunkTranslator(self) - self.currentDupeNames = DuplicateNames( - for: ty.initializers + ty.variables + ty.methods, - config: self.config, - lookupContext: self.lookupContext - ) + self.currentDupeNames = DuplicateNames(for: ty.initializers + ty.variables + ty.methods) printer.print( """ diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index 1a877e769..d5b20ed32 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -39,7 +39,7 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator { var translatedDecls: [ImportedFunc: TranslatedFunctionDecl?] = [:] /// The set of method base names that have Java naming conflicts for the current type/module being generated. - var currentDupeNames: DuplicateNames = DuplicateNames(_bootstrap: []) + var currentDupeNames: DuplicateNames = DuplicateNames(for: []) /// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet, /// and write an empty file for those. @@ -172,11 +172,7 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) - self.currentDupeNames = DuplicateNames( - for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, - config: self.config, - lookupContext: self.lookupContext - ) + self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) printModuleClass(&printer) { printer in for decl in analysis.importedGlobalVariables { @@ -196,11 +192,7 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) // TODO: we could have some imports be driven from types used in the generated decl - self.currentDupeNames = DuplicateNames( - for: decl.initializers + decl.variables + decl.methods, - config: self.config, - lookupContext: self.lookupContext - ) + self.currentDupeNames = DuplicateNames(for: decl.initializers + decl.variables + decl.methods) printNominal(&printer, decl) { printer in // We use a static field to abuse the initialization order such that by the time we get type metadata, // we already have loaded the library where it will be obtained from. From eb98a8c4c469cdd3f727084553573ef0f354b037 Mon Sep 17 00:00:00 2001 From: clemo97 Date: Mon, 9 Mar 2026 19:10:09 +0300 Subject: [PATCH 5/5] jextract/ffm: Fix duplicate detection to check Java method signatures Changed DuplicateNames conflict detection to compare Swift-level parameter types instead of just base names. Only methods that can be successfully lowered (via CdeclLowering) are considered for conflict detection. Previously, methods like Data.init(bytes:count:) and Data.init(_:) were both marked as duplicates because they share the same base name, even though they have different Swift/Java parameter types and do not conflict in Java. Also updates: - HelloJava2Swift.java: use Data.init() instead of Data.init_bytes_count() - FFMSwift2JavaGenerator+FoundationData.swift: use Data.init() instead of Data.init__() in the fromByteArray helper Fixes DataImportTests failures introduced by PR #544. --- .../com/example/swift/HelloJava2Swift.java | 6 +-- ...FMSwift2JavaGenerator+FoundationData.swift | 2 +- ...MSwift2JavaGenerator+JavaTranslation.swift | 51 +++++++++++++++---- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 10 +++- .../FFM/FFMSwift2JavaGenerator.swift | 12 +++-- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index 6b835a05a..a6619fc84 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -83,8 +83,8 @@ static void examples() { // Example of using 'Data'. try (var arena = AllocatingSwiftArena.ofConfined()) { var origBytes = arena.allocateFrom("foobar"); - var origDat = Data.init_bytes_count(origBytes, origBytes.byteSize(), arena); - CallTraces.trace("origDat.count = " + origDat.getCount()); + var origDat = Data.init(origBytes, origBytes.byteSize(), arena); + CallTraces.trace("origDat.count = " + origDat.getCount()); var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena); retDat.withUnsafeBytes((retBytes) -> { @@ -95,7 +95,7 @@ static void examples() { try (var arena = AllocatingSwiftArena.ofConfined()) { var bytes = arena.allocateFrom("hello"); - var dat = Data.init_bytes_count(bytes, bytes.byteSize(), arena); + var dat = Data.init(bytes, bytes.byteSize(), arena); MySwiftLibrary.globalReceiveSomeDataProtocol(dat); MySwiftLibrary.globalReceiveOptional(OptionalLong.of(12), Optional.of(dat)); } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift index 136f3bc68..b3fa1b30b 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+FoundationData.swift @@ -40,7 +40,7 @@ extension FFMSwift2JavaGenerator { */ public static \(typeName) fromByteArray(byte[] bytes, AllocatingSwiftArena arena) { Objects.requireNonNull(bytes, "bytes cannot be null"); - return \(typeName).init__(bytes, arena); + return \(typeName).init(bytes, arena); } """ ) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index 50f4d1227..ce569ce84 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -49,9 +49,17 @@ extension FFMSwift2JavaGenerator { struct DuplicateNames { private var duplicates: Set = [] - /// Detects which base names among `methods` would clash in Java. - init(for methods: [ImportedFunc]) { - var seen: Set = [] + /// Creates an empty DuplicateNames with no conflicts detected. + /// Used as the default/placeholder value before real conflict detection is performed. + init() {} + + /// Detects which base names among `methods` would clash in Java, + /// using Swift-level parameter types to determine conflicts. + /// Two methods conflict only if they share the same base name AND have the same + /// Swift parameter types (which implies they'll produce the same Java parameter types). + /// Methods that are untranslatable (failed CdeclLowering) are excluded from detection. + init(for methods: [ImportedFunc], knownTypes: SwiftKnownTypes) { + var methodsByBaseName: [String: [ImportedFunc]] = [:] for method in methods { let baseName = switch method.apiKind { @@ -59,8 +67,28 @@ extension FFMSwift2JavaGenerator { case .setter, .subscriptSetter: method.javaSetterName case .function, .synthesizedFunction, .initializer, .enumCase: method.name } - if !seen.insert(baseName).inserted { - duplicates.insert(baseName) + methodsByBaseName[baseName, default: []].append(method) + } + + for (baseName, groupedMethods) in methodsByBaseName where groupedMethods.count > 1 { + // Only consider methods that can actually be lowered/translated. + let lowering = CdeclLowering(knownTypes: knownTypes) + let translatableMethods = groupedMethods.filter { + (try? lowering.lowerFunctionSignature($0.functionSignature)) != nil + } + + // Detect actual conflicts by comparing Swift parameter type signatures. + // Two methods with the same Swift parameter types will produce the same Java types. + var seenSignatures: Set = [] + for method in translatableMethods { + let key = method.functionSignature.parameters + .map { $0.type.description } + .joined(separator: ",") + if !seenSignatures.insert(key).inserted { + // Two translatable methods share both the base name and Swift parameter types → Java conflict. + duplicates.insert(baseName) + break + } } } } @@ -179,7 +207,7 @@ extension FFMSwift2JavaGenerator { var knownTypes: SwiftKnownTypes var dupeNames: DuplicateNames - init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames(for: [])) { + init(config: Configuration, knownTypes: SwiftKnownTypes, dupeNames: DuplicateNames = DuplicateNames()) { self.config = config self.knownTypes = knownTypes self.dupeNames = dupeNames @@ -225,11 +253,12 @@ extension FFMSwift2JavaGenerator { /// Returns the Java method name for the given Swift declaration, applying parameter /// label suffixes only when a naming conflict with another method would occur. private func makeJavaMethodName(_ decl: ImportedFunc) -> String { - let baseName = switch decl.apiKind { - case .getter, .subscriptGetter: decl.javaGetterName - case .setter, .subscriptSetter: decl.javaSetterName - case .function, .synthesizedFunction, .initializer, .enumCase: decl.name - } + let baseName = + switch decl.apiKind { + case .getter, .subscriptGetter: decl.javaGetterName + case .setter, .subscriptSetter: decl.javaSetterName + case .function, .synthesizedFunction, .initializer, .enumCase: decl.name + } return baseName + makeMethodNameWithParamsSuffix(decl, baseName: baseName) } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index 0f1ea6234..595fea0f4 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -122,7 +122,10 @@ extension FFMSwift2JavaGenerator { self.lookupContext.symbolTable.printImportedModules(&printer) - self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) + self.currentDupeNames = DuplicateNames( + for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + ) for thunk in stt.renderGlobalThunks() { printer.print(thunk) printer.println() @@ -141,7 +144,10 @@ extension FFMSwift2JavaGenerator { package func printSwiftThunkSources(_ printer: inout CodePrinter, ty: ImportedNominalType) throws { let stt = SwiftThunkTranslator(self) - self.currentDupeNames = DuplicateNames(for: ty.initializers + ty.variables + ty.methods) + self.currentDupeNames = DuplicateNames( + for: ty.initializers + ty.variables + ty.methods, + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + ) printer.print( """ diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index d5b20ed32..9f3d06255 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -39,7 +39,7 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator { var translatedDecls: [ImportedFunc: TranslatedFunctionDecl?] = [:] /// The set of method base names that have Java naming conflicts for the current type/module being generated. - var currentDupeNames: DuplicateNames = DuplicateNames(for: []) + var currentDupeNames: DuplicateNames = DuplicateNames() /// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet, /// and write an empty file for those. @@ -172,7 +172,10 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) - self.currentDupeNames = DuplicateNames(for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables) + self.currentDupeNames = DuplicateNames( + for: self.analysis.importedGlobalFuncs + self.analysis.importedGlobalVariables, + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + ) printModuleClass(&printer) { printer in for decl in analysis.importedGlobalVariables { @@ -192,7 +195,10 @@ extension FFMSwift2JavaGenerator { printPackage(&printer) printImports(&printer) // TODO: we could have some imports be driven from types used in the generated decl - self.currentDupeNames = DuplicateNames(for: decl.initializers + decl.variables + decl.methods) + self.currentDupeNames = DuplicateNames( + for: decl.initializers + decl.variables + decl.methods, + knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + ) printNominal(&printer, decl) { printer in // We use a static field to abuse the initialization order such that by the time we get type metadata, // we already have loaded the library where it will be obtained from.