From 824d1ac5567a894032411f5564f613259a46d18b Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Thu, 9 Apr 2015 12:15:46 +0300 Subject: [PATCH] Fix for KT-7306: Implicit array conversions cause ClassCastException at runtime #KT-7306 Fixed --- .../kotlin/codegen/state/JetTypeMapper.java | 37 +++++++++++-------- .../arrays/inProjectionAsParameter.kt | 9 +++++ .../arrays/inProjectionOfArray.kt | 10 +++++ .../arrays/inProjectionOfList.kt | 10 +++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 18 +++++++++ 5 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/arrays/inProjectionAsParameter.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfArray.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfList.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index 2feb61dff90..ddb274dd1f1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -187,7 +187,7 @@ public class JetTypeMapper { return mapType(descriptor.getReturnType(), sw, JetTypeMapperMode.TYPE_PARAMETER); } else { - return mapType(returnType, sw, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE, false); + return mapType(returnType, sw, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE); } } @@ -229,7 +229,7 @@ public class JetTypeMapper { @NotNull private Type mapType(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode mode) { - return mapType(jetType, signatureVisitor, mode, Variance.INVARIANT, false); + return mapType(jetType, signatureVisitor, mode, Variance.INVARIANT); } @NotNull @@ -237,8 +237,7 @@ public class JetTypeMapper { @NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode kind, - @NotNull Variance howThisTypeIsUsed, - boolean arrayParameter + @NotNull Variance howThisTypeIsUsed ) { Type known = null; DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); @@ -256,7 +255,7 @@ public class JetTypeMapper { return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed); } else if (kind == JetTypeMapperMode.TYPE_PARAMETER || kind == JetTypeMapperMode.SUPER_TYPE) { - return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed, arrayParameter, projectionsAllowed); + return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed, projectionsAllowed); } else if (kind == JetTypeMapperMode.IMPL) { // TODO: enable and fix tests @@ -295,13 +294,25 @@ public class JetTypeMapper { TypeProjection memberProjection = jetType.getArguments().get(0); JetType memberType = memberProjection.getType(); - if (signatureVisitor != null) { - signatureVisitor.writeArrayType(); - mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER, memberProjection.getProjectionKind(), true); - signatureVisitor.writeArrayEnd(); + Type arrayElementType; + if (memberProjection.getProjectionKind() == Variance.IN_VARIANCE) { + arrayElementType = AsmTypes.OBJECT_TYPE; + if (signatureVisitor != null) { + signatureVisitor.writeArrayType(); + signatureVisitor.writeAsmType(arrayElementType); + signatureVisitor.writeArrayEnd(); + } + } + else { + arrayElementType = boxType(mapType(memberType, kind)); + if (signatureVisitor != null) { + signatureVisitor.writeArrayType(); + mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER, memberProjection.getProjectionKind()); + signatureVisitor.writeArrayEnd(); + } } - return Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor()); + return Type.getType("[" + arrayElementType.getDescriptor()); } if (descriptor instanceof ClassDescriptor) { @@ -462,7 +473,7 @@ public class JetTypeMapper { @Nullable BothSignatureWriter signatureVisitor, @NotNull Variance howThisTypeIsUsed ) { - return mapKnownAsmType(jetType, asmType, signatureVisitor, howThisTypeIsUsed, false, true); + return mapKnownAsmType(jetType, asmType, signatureVisitor, howThisTypeIsUsed, true); } private Type mapKnownAsmType( @@ -470,14 +481,10 @@ public class JetTypeMapper { Type asmType, @Nullable BothSignatureWriter signatureVisitor, @NotNull Variance howThisTypeIsUsed, - boolean arrayParameter, boolean allowProjections ) { if (signatureVisitor != null) { if (jetType.getArguments().isEmpty()) { - if (arrayParameter && howThisTypeIsUsed == Variance.IN_VARIANCE) { - asmType = AsmTypes.OBJECT_TYPE; - } signatureVisitor.writeAsmType(asmType); } else { diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionAsParameter.kt b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionAsParameter.kt new file mode 100644 index 00000000000..e70e5ad4292 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionAsParameter.kt @@ -0,0 +1,9 @@ +fun test(y: Array>) { + y[0] = kotlin.array("OK") +} + +fun box() : String { + val x : Array> = kotlin.array(kotlin.array(1)) + test(x) + return x[0][0] as String +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfArray.kt b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfArray.kt new file mode 100644 index 00000000000..7d1a9988b6a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfArray.kt @@ -0,0 +1,10 @@ +fun box(): String { + val x : Array> = array(array(1)) + val y : Array> = x + + if (y.size() != 1) return "fail 1" + + y[0] = array("OK") + + return x[0][0] as String +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfList.kt b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfList.kt new file mode 100644 index 00000000000..2a3d23ba837 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfList.kt @@ -0,0 +1,10 @@ +fun box(): String { + val x: Array> = array(listOf(1)) + val y : Array> = x + + if (y.size() != 1) return "fail 1" + + y[0] = listOf("OK") + + return x[0][0] as String +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index f2462a1622e..64ff550ddbe 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -173,6 +173,24 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("inProjectionAsParameter.kt") + public void testInProjectionAsParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/inProjectionAsParameter.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("inProjectionOfArray.kt") + public void testInProjectionOfArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfArray.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("inProjectionOfList.kt") + public void testInProjectionOfList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/inProjectionOfList.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("indices.kt") public void testIndices() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/indices.kt");