java.lang.VerifyError occurs. How do I fix it?

I got java.lang.VerifyError when I used some operator functions.
I don’t know why this error occurs.
Could you tell me how to fix it?

Error log:

Picked up JAVA_TOOL_OPTIONS: -Djava.io.tmpdir=/home/ubuntu_dev/.var/app/com.jetbrains.IntelliJ-IDEA-Community/cache/tmp/
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    com/example/MainKt.plusAssign(Lcom/example/MutableDouble3;Lcom/example/Double3;)V @75: invokestatic
  Reason:
    Type 'com/example/Double3' (current frame, stack[0]) is not assignable to 'com/example/MutableDouble3'
  Current Frame:
    bci: @75
    flags: { }
    locals: { 'com/example/MutableDouble3', 'com/example/Double3', 'com/example/Double3', integer, integer, integer, double, double_2nd, integer, integer, integer, 'com/example/Double3' }
    stack: { 'com/example/Double3', integer, double, double_2nd }
  Bytecode:
    0x0000000: 2a12 45b8 004b 2b12 4db8 004b 2ac0 001f
    0x0000010: 4d03 3e03 3604 0636 0515 0415 05a2 0038
    0x0000020: 1504 2c15 04b8 0023 3906 3608 0336 092a
    0x0000030: c000 1f15 0836 0a3a 0b19 0b15 0a19 0b15
    0x0000040: 0ab8 0023 2b15 08b8 0023 63b8 003e 0084
    0x0000050: 0401 a7ff c700 b1                      
  Stackmap Table:
    full_frame(@25,{Object[#11],Object[#31],Object[#31],Integer,Integer,Integer},{})
    same_frame(@85)

	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
	at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
	at java.lang.Class.getMethod0(Class.java:3018)
	at java.lang.Class.getMethod(Class.java:1784)
	at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

Process finished with exit code 1

Source code:

// Kotlin 1.3.72

package com.example

// Please run main()
fun main() {
    val vector = MutableDouble3(1.0, 2.0, 3.0)
    println("vector[0] is ${vector[0]}")
    println("calling 'vector[0] = 4.0'")
    vector[0] = 4.0
    println("vector[0] is ${vector[0]}")
}

sealed class Double3 {
    abstract val x: Double
    abstract val y: Double
    abstract val z: Double
}

abstract class ReadonlyDouble3 : Double3()

class MutableDouble3(
    override var x: Double,
    override var y: Double,
    override var z: Double
) : Double3()

class ImmutableDouble3(
    override val x: Double,
    override val y: Double,
    override val z: Double
) : ReadonlyDouble3()

operator fun Double3.get(index: Int): Double = when (index) {
    0 -> x
    1 -> y
    2 -> z
    else -> throw IndexOutOfBoundsException("index=$index, validIndices=0..2")
}

operator fun MutableDouble3.set(index: Int, newValue: Double): Unit = when (index) {
    0 -> x = newValue
    1 -> y = newValue
    2 -> z = newValue
    else -> throw IndexOutOfBoundsException("index=$index, validIndices=0..2")
}

inline fun Double3.forEachIndexed(action: (index: Int, component: Double) -> Unit) {
    for (index in 0 until 3) {
        action(index, this[index])
    }
}

operator fun MutableDouble3.plusAssign(other: Double3): Unit = forEachIndexed { index, _ ->
    this[index] += other[index]
}

I don’t know why, but VerifyError doesn’t occur when I comment out the MutableDouble3.plusAssign function.

I decompiled the source code with the “Kotlin Bytecode” tool in IntelliJ IDEA.
(IntelliJ IDEA > Tools > Kotlin > Show Kotlin Bytecode)

I found the type of var11 in plusAssign is Double3.
Shouldn’t it be MutableDouble3?


   public static final void plusAssign(@NotNull MutableDouble3 $this$plusAssign, @NotNull Double3 other) {
      Intrinsics.checkParameterIsNotNull($this$plusAssign, "$this$plusAssign");
      Intrinsics.checkParameterIsNotNull(other, "other");
      Double3 $this$forEachIndexed$iv = (Double3)$this$plusAssign;
      int $i$f$forEachIndexed = false;
      int index$iv = 0;

      for(byte var5 = 3; index$iv < var5; ++index$iv) {
         get($this$forEachIndexed$iv, index$iv);
         int var9 = false;
         Double3 var11 = (Double3)$this$plusAssign;
         set(var11, index$iv, get(var11, index$iv) + get(other, index$iv));
      }

   }

This looks like a bug in the compiler. The compiler should not output byte code that fails verification.

1 Like

Very strange. If you change the plusAssign function a little bit it works:

operator fun MutableDouble3.plusAssign(other: Double3): Unit = forEachIndexed { index, _ ->
    this[index] =  this[index] + other[index]
}

My guess is that there is an error in the generated bytecode for plusAssign in combination with custom indexed getter/setter for a field with a primitive type (I hope that sentence makes sense).

I created a youtrack issue for this here: https://youtrack.jetbrains.com/issue/KT-40179

Thank you so much.

By the way, extension functions may be related to this error.
VerifyError does not occur when the get function is not an extension function.


sealed class Double3 {
    abstract val x: Double
    abstract val y: Double
    abstract val z: Double

    operator fun get(index: Int): Double = when (index) {
        0 -> x
        1 -> y
        2 -> z
        else -> throw IndexOutOfBoundsException("index=$index, validIndices=0..2")
    }
}


//operator fun Double3.get(index: Int): Double = when (index) {
//    0 -> x
//    1 -> y
//    2 -> z
//    else -> throw IndexOutOfBoundsException("index=$index, validIndices=0..2")
//}