diff --git a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/GenericType.swift b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/GenericType.swift index 420afda5..d3a0ff8b 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/GenericType.swift +++ b/Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/GenericType.swift @@ -88,6 +88,11 @@ public func makeIntGenericEnum() -> GenericEnum { if Bool.random() { return .foo } else { return .bar } } +public enum GenericEnumWithValue { + case some(T) + case none +} + extension MyID where T: BinaryInteger { // Conditional extension functions are not exported public func computeSomeValue() -> Int { diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index e9f13626..d46b748d 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -504,25 +504,40 @@ extension JNISwift2JavaGenerator { } printer.println() - let requiresSwiftArena = decl.cases.compactMap { - self.translatedEnumCase(for: $0) - }.contains(where: \.requiresSwiftArena) - - printer.printBraceBlock("public Case getCase(\(requiresSwiftArena ? "SwiftArena swiftArena" : ""))") { printer in - printer.printBraceBlock("return switch (this.getDiscriminator())", .semicolonNewLine) { printer in - for enumCase in decl.cases { - guard let translatedCase = self.translatedEnumCase(for: enumCase) else { - continue - } - if enumCase.parameters.isEmpty { - printer.print( - "case \(enumCase.name.uppercased()) -> new Case.\(translatedCase.name)();" - ) - } else { - let arenaArgument = translatedCase.requiresSwiftArena ? "swiftArena" : "" - printer.print( - "case \(enumCase.name.uppercased()) -> this.getAs\(translatedCase.name)(\(arenaArgument)).orElseThrow();" - ) + // Ensure all cases can be generated to avoid inconsistency with the discriminator. + let allCasesCanBeTranslated = decl.cases.allSatisfy({ + translatedEnumCase(for: $0) != nil + }) + if !allCasesCanBeTranslated { + printer.print( + """ + // This is unavailable because it contains unsupported cases. + private Case getCase() { + return null; + } + """ + ) + } else { + let requiresSwiftArena = decl.cases.compactMap { + self.translatedEnumCase(for: $0) + }.contains(where: \.requiresSwiftArena) + + printer.printBraceBlock("public Case getCase(\(requiresSwiftArena ? "SwiftArena swiftArena" : ""))") { printer in + printer.printBraceBlock("return switch (this.getDiscriminator())", .semicolonNewLine) { printer in + for enumCase in decl.cases { + guard let translatedCase = self.translatedEnumCase(for: enumCase) else { + continue + } + if enumCase.parameters.isEmpty { + printer.print( + "case \(enumCase.name.uppercased()) -> new Case.\(translatedCase.name)();" + ) + } else { + let arenaArgument = translatedCase.requiresSwiftArena ? "swiftArena" : "" + printer.print( + "case \(enumCase.name.uppercased()) -> this.getAs\(translatedCase.name)(\(arenaArgument)).orElseThrow();" + ) + } } } } diff --git a/Tests/JExtractSwiftTests/JNI/JNIGenericTypeTests.swift b/Tests/JExtractSwiftTests/JNI/JNIGenericTypeTests.swift index 5f82b3bd..5ccc68b4 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIGenericTypeTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIGenericTypeTests.swift @@ -252,6 +252,43 @@ struct JNIGenericTypeTests { ) } + @Test + func genericEnumWithAssociatedValue() throws { + let input = + #""" + public enum MyOptional { + case some(Wrapped) + case none + } + """# + + try assertOutput( + input: input, + .jni, + .java, + detectChunkByInitialLines: 2, + expectedChunks: [ + """ + public enum Discriminator { + SOME, + NONE + } + """, + """ + public sealed interface Case { + record None() implements Case {} + } + """, + """ + // This is unavailable because it contains unsupported cases. + private Case getCase() { + return null; + } + """, + ] + ) + } + @Test func nestedGenericType() throws { let input =