You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Kotlin Multiplatform: a Java call to a Kotlin object links the commonMain expect instead of the platform actual #3033
When a Java file calls into a Kotlin Multiplatform object, the call now links to the expect declaration in commonMain instead of the actual in the platform source set. An expect declaration doesn't exist in JVM bytecode, so a Java caller can only ever reach the actual.
Actual on main (60b0d7a): App.run calls lib/src/commonMain/kotlin/a/Util.kt: Util::go.
Regression
This changed with #3023, which made a Java call through an import reach the Kotlin class it names. Before that (01e0ac3), the same call linked to the androidMainactual. In a real project, JakeWharton/timber, Timber.plant(...) and Timber.tag(...) from the Java sample app moved from androidMain/.../Timber.kt to the commonMainexpect class Timber. So did extends Timber.Tree.
Possible direction: when an import names a class that has both expect and actual declarations, a Java caller (and a platform source set's Kotlin caller) should prefer the actual in a source set that caller can see.
Found by indexing the same repos with the builds before and after the recent JVM resolution fixes and diffing the edges.
Edited 2026-10-29: added the environment, the native-kernel check and the related issues. The repro and the expected and actual results are unchanged.
Environment: Linux (WSL2), Node 22.23.2. Reproduced on main at 60b0d7a both with CODEGRAPH_KERNEL=0 and with the native kernel.
Related: this changed with #3023, which made a Java call through an import reach the Kotlin class it names. #1676 is a separate feature request for a Kotlin Multiplatform bridge.
I reproduced this bug with root cause in src/resolution/import-resolver.ts — resolveJavaImportedReference (the JVM import resolution #3023 added) picks the imported declaration's owner with pickClosestJvmCandidate, which prefers an expect declaration on a directory-proximity tie, so a Java caller of a.Util lands on the commonMain expect instead of the platform actual. I plan to resolve it by making that pick caller-aware — a Java caller (whose JVM bytecode never contains the expect) and a Kotlin caller in a platform source set take the actual, the one in the caller's own source set when there is one, while a commonMain caller keeps the expect — without touching public API. Does this align with the project design?
Activity
johnhldiver-beep commentedon Oct 31, 2026
I reproduced this bug with root cause in
src/resolution/import-resolver.ts—resolveJavaImportedReference(the JVM import resolution #3023 added) picks the imported declaration's owner withpickClosestJvmCandidate, which prefers anexpectdeclaration on a directory-proximity tie, so a Java caller ofa.Utillands on the commonMainexpectinstead of the platformactual. I plan to resolve it by making that pick caller-aware — a Java caller (whose JVM bytecode never contains theexpect) and a Kotlin caller in a platform source set take theactual, the one in the caller's own source set when there is one, while a commonMain caller keeps theexpect— without touching public API. Does this align with the project design?fix(kotlin): a Multiplatform import reaches what the caller compiles …