Skip to content

fix: support Kotlin 2.4.0 by building against the 2.4.0 compiler API#32

Merged
wilmveel merged 2 commits into
mainfrom
claude/eager-cannon-oyomch
Jun 16, 2026
Merged

fix: support Kotlin 2.4.0 by building against the 2.4.0 compiler API#32
wilmveel merged 2 commits into
mainfrom
claude/eager-cannon-oyomch

Conversation

@nsmnds

@nsmnds nsmnds commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Fixes #31

Problem

kmapper 0.0.15 crashes the Kotlin 2.4.0 compiler during plugin registration:

java.lang.ClassCastException: class org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter$Companion
cannot be cast to class org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor

Kotlin 2.4.0 replaced ProjectExtensionDescriptor with a new ExtensionPointDescriptor type in the CompilerPluginRegistrar.ExtensionStorage API (FirExtensionRegistrarAdapter.Companion and IrGenerationExtension.Companion now extend the new type). The kmapper source is already correct — the published binary was just compiled against the old hierarchy, so its checkcast ProjectExtensionDescriptor fails at runtime on 2.4.0. The fix is to build and publish against Kotlin 2.4.0.

Changes

  • Bump Kotlin 2.3.20 → 2.4.0 in all modules (root, compiler-plugin, compiler-runtime, gradle-plugin via root, test-integration, benchmarks). The recompiled registrar now emits registerExtension(ExtensionPointDescriptor, ...) (verified via javap).
  • Fix a latent IR bug surfaced by 2.4.0: the lambdas synthesized for List mappings were created without an initialized parent, which 2.4.0's IR lowering rejects (IllegalStateException: Parent of element ... is not initialized). KMapperExtension now calls patchDeclarationParents() after the transform. This was caught by ListMappingTest.shouldCompile_complexList and shouldCompile_valueClassUnwrapInList once the integration tests ran on 2.4.0.
  • Enforce Kotlin 2.4.0 as the minimum supported version: the compiler plugin built against the 2.4 API cannot load on older compilers, so the Gradle plugin now fails fast at apply time with a clear message when the project's Kotlin Gradle Plugin is older than 2.4.0 (instead of the 2.3.x mirror image of this issue's crash). Covered by a new KotlinVersionGuardTest that applies the plugin to a Kotlin 2.3.21 TestKit project.
  • Stop silently overriding the consumer's Kotlin version: kotlin-gradle-plugin-api is now compileOnly. It used to be implementation, which put a 2.x-pinned runtime dependency in the published POM — KGP's BOM alignment then silently upgraded the consumer's entire Kotlin Gradle Plugin to kmapper's Kotlin version, masking incompatibilities instead of surfacing them. With compileOnly the consumer's own KGP stays in control and the version guard sees the version the project actually asked for.
  • Box-test setup: com.gradleup.kctf:kctf-runtime is not published for Kotlin 2.4, and its single class was compiled when KotlinStandardLibrariesPathProvider was still an abstract class — 2.4.0 turned it into an interface, causing IncompatibleClassChangeError. The compiler test framework is now depended on directly at the project's Kotlin version, and kctf's classpath-based path provider (MIT) is vendored into the test sources (same kctf package, so the kctf-generated test source keeps working).
  • Dropped -Xcontext-parameters, which is enabled by default (and reported as redundant) with language version 2.4.
  • Integration tests now provision Kotlin 2.4.0 TestKit projects — the end-to-end reproduction of the reported scenario — and the README documents 2.4.0 as the minimum.

Verification

  • ./gradlew build — green (compiler-plugin box tests + all 73 TestKit integration tests, including the new minimum-version guard test).
  • ./gradlew -Pkmapper.benchmarks=true :benchmarks:verifyBenchmarkThresholds — green (kmapper vs manual ratio 0.98x / 0.99x).
  • javap on the rebuilt KMapperCompilerPluginRegistrar confirms the new ExtensionPointDescriptor-based registration that 2.4.0 expects.
  • Manually verified the guard: a Kotlin 2.3.21 project applying the plugin fails configuration with kmapper requires Kotlin 2.4.0 or newer, but this project uses Kotlin 2.3.21 ....

https://claude.ai/code/session_01SgLsvFcF9CfGLkLbYG267U

claude added 2 commits June 11, 2026 12:14
Kotlin 2.4.0 replaced ProjectExtensionDescriptor with ExtensionPointDescriptor
in the CompilerPluginRegistrar extension-storage API, so the plugin binary
built against older Kotlin crashes registration with a ClassCastException
(FirExtensionRegistrarAdapter$Companion cannot be cast to
ProjectExtensionDescriptor). Rebuilding against 2.4.0 emits the new
registerExtension(ExtensionPointDescriptor, ...) call.

Other changes needed to get the build green on 2.4.0:

- Patch declaration parents after the IR transform: the lambdas synthesized
  for List mappings were created without a parent, which 2.4.0 IR lowering
  now rejects (IllegalStateException: parent not initialized).
- Depend on the Kotlin compiler test framework directly and vendor kctf's
  ClasspathBasedStandardLibrariesPathProvider (MIT): kctf-runtime is not
  published for Kotlin 2.4 and its provider was compiled when
  KotlinStandardLibrariesPathProvider was still a class, which 2.4.0 turned
  into an interface (IncompatibleClassChangeError).
- Drop -Xcontext-parameters, which is redundant with language version 2.4.
- Run the TestKit integration tests and document the README against 2.4.0.

Fixes #31
The compiler plugin is built against the Kotlin 2.4 compiler API and cannot
be loaded by older compilers. Instead of letting 2.3.x users hit an obscure
crash (the mirror image of #31), the Gradle plugin now fails fast at apply
time with a clear message when the project's Kotlin Gradle Plugin is older
than 2.4.0.

Also scope kotlin-gradle-plugin-api as compileOnly. With implementation
scope the published POM carried a runtime dependency on the API plus a
2.4.0 dependencyManagement pin, and KGP's BOM alignment then silently
upgraded the consumer's entire Kotlin Gradle Plugin to 2.4.0 even when the
project requested an older version — masking the incompatibility instead of
surfacing it. With compileOnly the consumer's own KGP stays in control and
the version check sees the version the project actually asked for.

Covered by a new integration test that applies the plugin to a Kotlin
2.3.21 TestKit project and asserts the clear failure message.
@wilmveel wilmveel merged commit c3cf2ba into main Jun 16, 2026
2 checks passed
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.

Compiler plugin crashes with ClassCastException on Kotlin 2.4.0

3 participants