Очень загадочная ошибка времени выполнения: операнд Bad type в стеке

Я получаю эту загадочную ошибку:

java.lang.VerifyError: Bad type on operand stack Exception Details: Location: org/bh/tools/base/strings/TestUtils.concat(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; @28: invokevirtual Reason: Type 'java/lang/Object' (current frame, stack[1]) is not assignable to 'java/lang/String' Current Frame: bci: @28 flags: { } locals: { 'java/lang/Object', 'java/lang/CharSequence' } stack: { 'java/lang/StringBuilder', 'java/lang/Object' } Bytecode: 0x0000000: 2a12 59b8 0012 2b12 43b8 0012 2ac1 005b 0x0000010: 9900 1a2a bb00 1659 b700 1a5f b600 512b 0x0000020: b600 5eb6 0052 c000 23b0 2ac1 0016 9900 0x0000030: 152a c000 162b b600 5e59 1260 b800 63c0 0x0000040: 0023 b0bb 0016 59b7 001a 2ab6 0047 2bb6 0x0000050: 005e 5912 65b8 0063 c000 23b0 Stackmap Table: same_frame(@42) same_frame(@67) at org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose(NumberConversionKtTest.kt:488) at org.bh.tools.base.math.NumberConversionKtTest.Number_float32Value(NumberConversionKtTest.kt:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:58) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 

На этой строке: https://github.com/BlueHuskyStudios/Blue-Base/blob/ea415b702b87b7a33d90bc13221f44205c38e9f1/JVM/test/org/bh/tools/base/math/NumberConversionKtTest.kt#L488

Я думаю, что эта функция включает в себя эту функцию: https://github.com/BlueHuskyStudios/Blue-Base/blob/ea415b702b87b7a33d90bc13221f44205c38e9f1/JVM/src/org/bh/tools/base/strings/String%20Utils.kt#L121-L154

но я не могу понять, что происходит не так. Кажется, я указываю, что я CharSequence метод concatenate для Object и CharSequence в классе TestUtils (который, как мне кажется, не затрагивается при запуске теста, который вызывает это ), но звучит очень близко к другой функции, которую я написал который здесь не использовался.

Что-то происходит, я не могу опустить голову. У кого-нибудь есть идеи?


Ошибка Companion JetBrains: KT-17210

Поскольку у меня нет байт-кода для изучения, все приведенные ниже объяснения основаны на одном предположении: у Котлина снова есть умный персонаж.

tl; dr JVM проверяет весь класс вместо используемой пропорции.

Ситуация происходит в следующих шагах:

  1. Тест прошел. Junit обнаружил тесты и попытался вызвать org.bh.tools.base.math.NumberConversionKtTest::Number_float32Value отражение. Это вызвало загрузку, связывание и инициализацию класса NumberConversionKtTest . Все в порядке.
  2. Этот метод вызывается org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose , который находится внутри еще не загруженного класса (обратите внимание на пробную версию Kt которой не был предыдущий класс). JVM найден, загружен, связан и инициализирован.
  3. Теперь assertNumbersClose , т. assertNumbersClose новый кадр и помещается в стек. После выполнения некоторого байт-кода поток программы переместился в строку 488 и нашел инструкцию вызова метода, которая просит JVM выполнить метод, лежащий в классе org.bh.tools.base.strings.TestUtils . Этот класс еще не загружался, поэтому JVM начал загружать новый класс.
  4. JVM загружает этот класс, и, во время проверки , он обнаружил, что метод concat , а не тот, который используется в assertNumbersClose , не является хорошим. Он останавливает проверку с помощью VerifyError . Поскольку метод differingCharacters еще не был выполнен, т. Е. Новый кадр не был создан и помещен в стек, он не находится в стеке, поэтому вы видите org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose сверху.

Положительное обходное решение

Вам нужно как-то исправить байт-код метода concat . У вас есть следующие wrokaround.

  1. Попробуйте обновить компилятор kotlin. Я помню, что некоторые проблемы, связанные с smartcast, были зафиксированы в kotlin 1.1.
  2. Поскольку эта ошибка является компилятором kotlin, не позволяющим передавать CHECKCAST для smartcasts, вы можете попробовать добавить ручной режим, например:

     fun concat(lhs: Any, rhs: CharSequence): CharSequence { if (lhs is String) { val s: String = lhs as String return s.plus(rhs) } else if (lhs is StringBuilder) { val sb: StringBuilder= lhs as StringBuilder return sb.append(rhs) } else { return StringBuilder().append(lhs).append(rhs) } } 

    Иногда это работает для некоторых людей.

  3. Если все это не работает, перейдите на обычную Java и поместите concat в другой класс. Это исправляет большинство, если не все, проблем kotlin.

По словам Дмитрия Петрова и Александра Черникова , это ошибка компилятора в Kotlin 1.1.1, которая исправлена ​​в выпуске 1.1.2.