Repository navigation
JNI: qualify enum payload types shadowed by Case record names - #5
Open
piercifani wants to merge 2 commits into
Open
piercifani wants to merge 2 commits into
piercifani wants to merge 2 commits into
Conversation
This was referenced Nov 3, 2026
piercifani
force-pushed
the
jni/04-enum-case-name-collision
branch
from
November 3, 2026 14:41
3d9a1fe to
beb8a93
Compare
piercifani
force-pushed
the
jni/04-enum-case-name-collision
branch
from
November 3, 2026 15:19
beb8a93 to
9f1a410
Compare
piercifani
force-pushed
the
jni/04-enum-case-name-collision
branch
from
November 3, 2026 15:56
9f1a410 to
888b7d5
Compare
Inside the generated `sealed interface Case`, each record's name shadows a type with the same simple name. For `case market(Market)` the record became `record Market(Market arg0)`, whose component referred to the record itself, and the generated Java didn't compile. The same happened when another case's record had the payload's name, including for arrays. Fully qualify package-less component types (types generated into this module's Java package) whose leading name matches a record, recursively through arrays and type arguments. Generic parameters and unshadowed payloads are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
piercifani
force-pushed
the
jni/04-enum-case-name-collision
branch
from
November 3, 2026 16:46
888b7d5 to
a0aa245
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 4/21 · base:
jni/03-skipped-declarations· previous: #3 · next: #6Problem
For an enum with associated values, JNI mode generates a
sealed interface Casewith one record per case. Inside that interface, each record's name shadows any type with the same simple name, so a case named like its payload type produces Java that doesn't compile:The same happens when one case's payload is named like another case's record (
case marketpluscase featured(Market)), and for arrays of that type.Changes
When printing the
Caserecords, any package-less component type whose leading name matches one of the records is fully qualified with the module's Java package, recursively through arrays and type arguments:Package-less types are the ones jextract generates into the module's package: jextracted types plus
Date,DataandURL. Generic parameters of the enum are never qualified. Payloads with no collision are printed as before.Why Skip needs it
Naming a case after its payload type is a common Swift pattern. A production Skip Fuse app (16 Skip modules) has 33 such cases in its bridged enums.
Kotlin in this PR
EnumCaseNamesTest.ktwithEnumCaseNames.swift:getCase()oncase market(Market), and on an enum where another case's record shadows the payload type, including an array of it.Testing
./gradlew :Samples:SwiftJavaExtractJNIKotlinSampleApp:testpasses at this point in the stack.JNIEnumCaseNameShadowingTests: a case named like its payload, another case's record shadowing a payload (including an array), and an unshadowed control. Both collision tests fail on the base branch; the control passes on both.StructHolderenum withcase mySwiftStruct(MySwiftStruct)and a Java test reading the payload throughgetCase.swift test --disable-experimental-prebuilts --disable-sandboxand./gradlew :Samples:SwiftJavaExtractJNISampleApp:testpass.swift format lint --stricton changed files;git diff --check.Not in this PR
A payload type named
CaseorDiscriminatorwould collide with the generated member types of the enum class itself; that isn't handled.🤖 Generated with Claude Code