Fix CCE in generated code that happens when comparing boxed chars

The problem was that when obtaining char from the wrapper,
codegen used int as expected type that led
to a ClassCastException: java.lang.Character cannot be cast to java.lang.Number

The solution is using coercion to chars, it's still correct,
because of implicit widening coercion in JVM from C to I

 #KT-15105 Fixed
This commit is contained in:
Denis Zharkov
2017-02-20 12:53:12 +03:00
parent 378acbf7ec
commit 85f9e2e47b
7 changed files with 41 additions and 1 deletions
@@ -770,6 +770,7 @@ public class AsmUtil {
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
if (left == Type.CHAR_TYPE || right == Type.CHAR_TYPE) return Type.CHAR_TYPE;
return Type.INT_TYPE;
}
@@ -25,7 +25,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class CompareTo : IntrinsicMethod() {
private fun genInvoke(type: Type?, v: InstructionAdapter) {
when (type) {
Type.INT_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
Type.INT_TYPE, Type.CHAR_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
Type.LONG_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(JJ)I", false)
Type.FLOAT_TYPE -> v.invokestatic("java/lang/Float", "compare", "(FF)I", false)
Type.DOUBLE_TYPE -> v.invokestatic("java/lang/Double", "compare", "(DD)I", false)
@@ -0,0 +1,16 @@
fun <T> id(x: T) = x
fun box(): String {
if (id('a') > id('b')) return "fail 1"
if (id('a') >= id('b')) return "fail 2"
if (id('b') < id('a')) return "fail 3"
if (id('b') <= id('a')) return "fail 4"
val x = id('a').compareTo('b')
if (x != -1) return "fail 5"
val y = id('b').compareTo('a')
if (y != 1) return "fail 6"
return "OK"
}
@@ -0,0 +1,5 @@
@kotlin.Metadata
public final class CompareBoxedCharsKt {
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method id(p0: java.lang.Object): java.lang.Object
}
@@ -785,6 +785,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("compareBoxedChars.kt")
public void testCompareBoxedChars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareBoxedChars.kt");
doTest(fileName);
}
@TestMetadata("compareWithBoxedDouble.kt")
public void testCompareWithBoxedDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareWithBoxedDouble.kt");
@@ -785,6 +785,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("compareBoxedChars.kt")
public void testCompareBoxedChars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareBoxedChars.kt");
doTest(fileName);
}
@TestMetadata("compareWithBoxedDouble.kt")
public void testCompareWithBoxedDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareWithBoxedDouble.kt");
@@ -977,6 +977,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("compareBoxedChars.kt")
public void testCompareBoxedChars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareBoxedChars.kt");
doTest(fileName);
}
@TestMetadata("compareWithBoxedDouble.kt")
public void testCompareWithBoxedDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/binaryOp/compareWithBoxedDouble.kt");