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

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/src/org/bh/tools/base/strings/Stkt#1l1 <1/1/1>1l1

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

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


Ошибка компаньона JetBrains: KT-17210

2
Supuhstar 2 Апр 2017 в 07:39

2 ответа

Лучший ответ

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

1
Supuhstar 27 Ноя 2017 в 01:54

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

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 теперь выполняется, то есть создается новый кадр и помещается в стек. После выполнения некоторого байт-кода поток программы переместился на строку 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. Я помню некоторые проблемы со смарткастами, которые были исправлены в 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.

1
glee8e 2 Апр 2017 в 12:40