diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java index abec8001ec1..edf964bc907 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -50,6 +50,7 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { case Type.SHORT: return SHORT_VALUE; case Type.OBJECT: + case Type.ARRAY: return new BasicValue(type); default: return super.newValue(type); @@ -78,13 +79,10 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { } // if merge of two references then `lub` is java/lang/Object - // arrays also are BasicValues with reference type's - if (v.getType().getSort() == Type.OBJECT && w.getType().getSort() == Type.OBJECT) { + if (isReference(v) && isReference(w)) { return BasicValue.REFERENCE_VALUE; } - assert v.getType().getSort() != Type.ARRAY && w.getType().getSort() != Type.ARRAY : "There should not be arrays"; - // if merge of something can be stored in int var (int, char, boolean, byte, character) if (v.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE && w.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE) { @@ -93,4 +91,8 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { return BasicValue.UNINITIALIZED_VALUE; } + + private static boolean isReference(@NotNull BasicValue v) { + return v.getType().getSort() == Type.OBJECT || v.getType().getSort() == Type.ARRAY; + } } diff --git a/compiler/testData/codegen/box/coroutines/kt12958.kt b/compiler/testData/codegen/box/coroutines/kt12958.kt new file mode 100644 index 00000000000..978b80c54a5 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/kt12958.kt @@ -0,0 +1,36 @@ +class Controller { + var result = "fail" + suspend fun suspendHere(v: V, x: Continuation) { + x.resume(v) + } + + operator fun handleResult(x: String, c: Continuation) { + result = x + } +} + +fun builder(coroutine c: Controller.() -> Continuation): String { + val controller = Controller() + c(controller).resume(Unit) + + return controller.result +} + +fun foo(): String = builder { + // A piece of code for next statement: + // INVOKEVIRTUAL suspendHere + // CHECKCAST [B + // + // Analyzer uses `newValue` method for estimation of type generated by CHECKCAST insn, + // but for arrays `newValue` returned just Basic.REFERENCE_VALUE, thus we didn't add necessary checkcasts + // for variables spilled into fields + val data2 = suspendHere(ByteArray(2)) + + suspendHere("") + data2.size.toString() +} + +fun box(): String { + if (foo() != "2") return "fail 1" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 443eab96765..ecb2629a266 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4201,6 +4201,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt12958.kt") + public void testKt12958() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt12958.kt"); + doTest(fileName); + } + @TestMetadata("lambdaParameters.kt") public void testLambdaParameters() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt");