Andrey Minogin

Reliability and Performance of LLM, JVM and Postgres systems

Kotlin IR: Unlocking Incredible Possibilities for Code Manipulation

Tree

I’m currently working on a pet project: a Kotlin assertion library designed to handle deep assertions over any object type. The goal is to write code that looks like this:

Kotlin
confirmThat { (1..3).toList() } deepMatches { listOf(1, 2, 3) }

To make this work, the library needs to convert arbitrary code into a structured matcher tree. Under the hood, the goal is to transform that simple list check into something like this:

Kotlin
confirmThat { (1..3).toList() } deepMatches {
    ListMatcher(
        ValueMatcher(1),
        ValueMatcher(2),
        ValueMatcher(3)
    )
}

To pull this off, I weighed two sophisticated technical paths:

Option 1: Runtime Bytecode Manipulation

The first option is to modify the compiled bytecode while the application is running using tools like Byte Buddy.

  • The Pro: It’s a standard way to handle introspection on the JVM without needing a custom compiler setup.
  • The Con: It has very limited capabilities because Kotlin-specific details — like null-safety metadata — are often erased or transformed once the code is compiled. Many things are just impossible — e.g. you cannot convert primitives (int) into objects (Int), which might make it impossible to replace int with IntMatcher.

Option 2: Kotlin Intermediate Representation (IR)

The more “hardcore” approach is hijacking the Kotlin compilation process itself. By using a Kotlin Compiler Plugin, I can intercept the IR (Intermediate Representation). This happens after the code is parsed but before it undergoes any “lowering” steps (converting high-level constructs into simpler ones) or gets turned into bytecode.

  • The Pro: This allows me to see the code in its purest form. I can generate highly efficient, type-safe matchers that are baked directly into the program.
  • The Con: It’s significantly more complex to implement since it requires working deep within the compiler’s internal mechanics.

My Take

I decided to go the “hardcore” route. I’ve been experimenting with Kotlin IR, and it works perfectly! It handles the primitive-to-object mapping and null-safety metadata with ease.

Stay tuned—I’ll be sharing more on how I actually implemented the IR transformer in my next post.


Have a problem like this in your own system? I start with two sessions on it — €2,000 fixed. How it works →

Andrey Minogin — software architect, 15+ years on data-intensive systems. I find out why a system in production is slow, expensive or wrong — in Java and Kotlin services, PostgreSQL and LLM workflows.

When the head of one of the world’s top PostgreSQL consultancies reviewed database work I had done, his conclusion after a day on site: there was nothing he could add.

Work with me · LinkedIn · andrey@minogin.com