From 0073257841426e777e8060f631e4b40fb8d7b007 Mon Sep 17 00:00:00 2001 From: Anton Sukhonosenko Date: Tue, 15 Dec 2015 08:54:09 +0300 Subject: [PATCH] Fix for KT-10313: ClassCastException with Generics #KT-10313 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 21 ++++++++- .../binaryExpressionCast.kt | 7 +++ .../labeledExpressionCast.kt | 7 +++ .../parenthesizedExpressionCast.kt | 7 +++ .../superConstructor.kt | 7 +++ .../unaryExpressionCast.kt | 7 +++ .../vararg.kt | 11 +++++ .../Box.java | 15 +++++++ .../literalExpressionAsGenericArgument.kt | 4 ++ .../lazyCodegen/negateConstantCompare.kt | 5 ++- .../BlackBoxCodegenTestGenerated.java | 45 +++++++++++++++++++ .../BlackBoxWithJavaCodegenTestGenerated.java | 6 +++ 12 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/binaryExpressionCast.kt create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/labeledExpressionCast.kt create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/parenthesizedExpressionCast.kt create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/superConstructor.kt create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/unaryExpressionCast.kt create mode 100644 compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/vararg.kt create mode 100644 compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/Box.java create mode 100644 compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/literalExpressionAsGenericArgument.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index f06791a0490..1d87a312814 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1242,12 +1242,21 @@ public class ExpressionCodegen extends KtVisitor impleme @Nullable public static ConstantValue getCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) { + return getCompileTimeConstant(expression, bindingContext, false); + } + + @Nullable + public static ConstantValue getCompileTimeConstant( + @NotNull KtExpression expression, + @NotNull BindingContext bindingContext, + boolean checkPure + ) { CompileTimeConstant compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext); if (compileTimeValue == null) { return null; } - if (compileTimeValue.getUsesNonConstValAsConstant()) return null; + if (compileTimeValue.getUsesNonConstValAsConstant() || (checkPure && !compileTimeValue.getParameters().isPure())) return null; KotlinType expectedType = bindingContext.getType(expression); return compileTimeValue.toConstantValue(expectedType); @@ -2893,6 +2902,11 @@ public class ExpressionCodegen extends KtVisitor impleme expression.getRight(), reference); } else { + ConstantValue compileTimeConstant = getCompileTimeConstant(expression, bindingContext, true); + if (compileTimeConstant != null) { + return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression)); + } + ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); @@ -3165,6 +3179,11 @@ public class ExpressionCodegen extends KtVisitor impleme @Override public StackValue visitPrefixExpression(@NotNull KtPrefixExpression expression, @NotNull StackValue receiver) { + ConstantValue compileTimeConstant = getCompileTimeConstant(expression, bindingContext, true); + if (compileTimeConstant != null) { + return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression)); + } + DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference()); ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); CallableDescriptor op = resolvedCall.getResultingDescriptor(); diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/binaryExpressionCast.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/binaryExpressionCast.kt new file mode 100644 index 00000000000..8f18303c58c --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/binaryExpressionCast.kt @@ -0,0 +1,7 @@ +class Box(val value: T) + +fun box() : String { + val b = Box(2 * 3) + val expected: Long? = 6L + return if (b.value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/labeledExpressionCast.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/labeledExpressionCast.kt new file mode 100644 index 00000000000..229afac35f9 --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/labeledExpressionCast.kt @@ -0,0 +1,7 @@ +class Box(val value: T) + +fun box() : String { + val b = Box(x@ (1 + 2)) + val expected: Long? = 3L + return if (b.value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/parenthesizedExpressionCast.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/parenthesizedExpressionCast.kt new file mode 100644 index 00000000000..a70372d5ca4 --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/parenthesizedExpressionCast.kt @@ -0,0 +1,7 @@ +class Box(val value: T) + +fun box() : String { + val b = Box((-1)) + val expected: Long? = -1L + return if (b.value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/superConstructor.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/superConstructor.kt new file mode 100644 index 00000000000..f896fd083f6 --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/superConstructor.kt @@ -0,0 +1,7 @@ +open class Base(val value: T) +class Box(): Base(-1) + +fun box(): String { + val expected: Long? = -1L + return if (Box().value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/unaryExpressionCast.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/unaryExpressionCast.kt new file mode 100644 index 00000000000..6f253b61557 --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/unaryExpressionCast.kt @@ -0,0 +1,7 @@ +class Box(val value: T) + +fun box() : String { + val b = Box(-1) + val expected: Long? = -1L + return if (b.value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/vararg.kt b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/vararg.kt new file mode 100644 index 00000000000..dab9ff62303 --- /dev/null +++ b/compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/vararg.kt @@ -0,0 +1,11 @@ +class Box(val value: T) + +fun run(vararg z: T): Box { + return Box(z[0]) +} + +fun box(): String { + val b = run(-1, -1, -1) + val expected: Long? = -1L + return if (b.value == expected) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/Box.java b/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/Box.java new file mode 100644 index 00000000000..98690d3ebb1 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/Box.java @@ -0,0 +1,15 @@ +public class Box { + private final T value; + + public Box(T value) { + this.value = value; + } + + public static Box create(T defaultValue) { + return new Box(defaultValue); + } + + public T getValue() { + return value; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/literalExpressionAsGenericArgument.kt b/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/literalExpressionAsGenericArgument.kt new file mode 100644 index 00000000000..c270553c35d --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/literalExpressionAsGenericArgument.kt @@ -0,0 +1,4 @@ +fun box(): String { + val sub = Box(-1) + return if (sub.value == -1L) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/lazyCodegen/negateConstantCompare.kt b/compiler/testData/codegen/bytecodeText/lazyCodegen/negateConstantCompare.kt index 931738dd0f7..dc3d86c0272 100644 --- a/compiler/testData/codegen/bytecodeText/lazyCodegen/negateConstantCompare.kt +++ b/compiler/testData/codegen/bytecodeText/lazyCodegen/negateConstantCompare.kt @@ -1,5 +1,8 @@ +const val one = 1 +const val two = 2 + fun test1() { - if (!(1 < 2)) { + if (!(one < two)) { val p = 1 } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 43b36cde54d..d7c7c3a5842 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -987,6 +987,51 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/unitNullableCast.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LiteralExpressionAsGenericArgument extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLiteralExpressionAsGenericArgument() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("binaryExpressionCast.kt") + public void testBinaryExpressionCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/binaryExpressionCast.kt"); + doTest(fileName); + } + + @TestMetadata("labeledExpressionCast.kt") + public void testLabeledExpressionCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/labeledExpressionCast.kt"); + doTest(fileName); + } + + @TestMetadata("parenthesizedExpressionCast.kt") + public void testParenthesizedExpressionCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/parenthesizedExpressionCast.kt"); + doTest(fileName); + } + + @TestMetadata("superConstructor.kt") + public void testSuperConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/superConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("unaryExpressionCast.kt") + public void testUnaryExpressionCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/unaryExpressionCast.kt"); + doTest(fileName); + } + + @TestMetadata("vararg.kt") + public void testVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/literalExpressionAsGenericArgument/vararg.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/classes") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index a8105208752..ac33b2b301b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -241,6 +241,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("literalExpressionAsGenericArgument") + public void testLiteralExpressionAsGenericArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/casts/literalExpressionAsGenericArgument/"); + doTestWithJava(fileName); + } + } @TestMetadata("compiler/testData/codegen/boxWithJava/collections")