Skip to content

fix(android): expose public types in Kotlin variant cases - #1998

Open
mrousavy wants to merge 1 commit into
mrousavy/v1-kotlin-ulongarrayfrom
mrousavy/v1-kotlin-variant-cases
Open

mrousavy wants to merge 1 commit into
mrousavy/v1-kotlin-ulongarrayfrom
mrousavy/v1-kotlin-variant-cases

Conversation

@mrousavy

@mrousavy mrousavy commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Second of five stacked PRs: #1997 → #1998 (this one) → #1999 → #2008 → #2009.

Kotlin variant case classes stored the type JNI uses instead of the public Kotlin type. For UInt64 | string, when (v) { is X.First -> v.value } gave a signed Long, so values above 2^63 came out negative, and X.First(5uL) didn't compile. A UInt64[] case held a LongArray, and a callback case held the generated Callback_* class, so constructing that case meant typing a Nitrogen specialization name.

Cases now hold their public type, e.g. ULong, ULongArray or Callback<...>, like Swift. fromCpp_<n> converts from the JNI value. JNI reads the value field directly when it already has the JNI representation, which covers ULong and ULongArray. Otherwise it calls a private getValue_cxx() accessor, like structs do. For callback cases that accessor uses Callback_*.fromKotlin(), which returns a callback that came from C++ unchanged, so create() no longer wraps the callback up front.

JNI calls these accessors, and the struct get<Field>_cxx() getters, with getNonvirtualMethod. Both are private and final, like the hybrid object _cxx bridges that already use it, so the virtual lookup was wasted.

New TestObject methods bounce UInt64 | string and UInt64[] | string variants. The Kotlin fixture rebuilds the ULong case through its constructor.

Validation: Kotlin compiles without warnings, javap shows the long and long[] fields and the createFirst(long) JVM name JNI expects, and the variant JNI sources compile with the NDK. I did not run the runtime tests locally.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
nitro-docs Skipped Skipped Oct 23, 2026 5:51pm UTC

Request Review

Kotlin variant case classes stored the type JNI uses instead of the
public Kotlin type. A UInt64 case held a Long, so values above 2^63 read
back negative and X.First(5uL) did not compile. A UInt64[] case held a
LongArray, and a callback case held the generated Callback_* class, so
constructing that case meant typing a Nitrogen specialization name.

Each case now holds its public type, e.g. ULong, ULongArray or
Callback<...>, and fromCpp_<n> converts from the JNI value. JNI reads the
value field directly when it already has the JNI representation, as for
ULong and ULongArray. Otherwise it calls a private getValue_cxx()
accessor, like structs do. A callback case converts with
Callback_*.fromKotlin(), which returns a callback that came from C++
unchanged.

JNI calls these accessors and the struct get<Field>_cxx() getters with
getNonvirtualMethod. Both are private and final, like the hybrid object
_cxx bridges that already use it.

New TestObject methods bounce UInt64 | string and UInt64[] | string
variants. The Kotlin fixture rebuilds the ULong case with its
constructor.

This branch was previously deployed

1 inactive deployment
Preview — 771aed0f Deployed Oct 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant