diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 3bca08e5e41..fd8ed0aabd0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -539,7 +539,17 @@ class ExpressionCodegen( ownerType.internalName } ?: typeMapper.mapClass(callee.parentAsClass).internalName return if (expression is IrSetField) { - expression.value.accept(this, data).materializeAt(fieldType, callee.type) + val value = expression.value.accept(this, data) + + // We only initialize enum entries with a subtype of `fieldType` and can avoid the CHECKCAST. + // This is important for some tools which analyze bytecode for enum classes by looking at the + // initializer of the $VALUES field. + if (callee.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) { + value.materialize() + } else { + value.materializeAt(fieldType, callee.type) + } + when { isStatic -> mv.putstatic(ownerName, fieldName, fieldType.descriptor) else -> mv.putfield(ownerName, fieldName, fieldType.descriptor) diff --git a/compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt b/compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt new file mode 100644 index 00000000000..6cbc5a8a212 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt @@ -0,0 +1,12 @@ +enum class Foo { + A, B, C { override fun result() = "OK" }; + open fun result() = "Fail" +} + +// JVM_TEMPLATES: +// There are two CHECKCASTs, one in Foo.valueOf and one in Foo.values +// 2 CHECKCAST + +// JVM_IR_TEMPLATES: +// There should be only one CHECKCAST in Foo.valueOf +// 1 CHECKCAST \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 1e6bd1a49e5..50bc0f19cd3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1855,6 +1855,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("enumCheckcasts.kt") + public void testEnumCheckcasts() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt"); + } + @TestMetadata("kt18731.kt") public void testKt18731() throws Exception { runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index a8f9535e53b..a45082c8037 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1810,6 +1810,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("enumCheckcasts.kt") + public void testEnumCheckcasts() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt"); + } + @TestMetadata("kt18731.kt") public void testKt18731() throws Exception { runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");