diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index d9396631935..2dcd9999e7b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -36,7 +36,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; -import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType; import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo; @@ -514,7 +513,7 @@ public class AsmUtil { }); } - static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type, JvmTarget jvmTarget, boolean isInterface) { + static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type, JvmTarget jvmTarget) { if (type.getSort() == Type.ARRAY) { Type elementType = correctElementType(type); if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { @@ -525,7 +524,7 @@ public class AsmUtil { } } else if (type.getSort() == Type.OBJECT) { - iv.invokevirtual((isInterface ? AsmTypes.OBJECT_TYPE : type).getInternalName(), "hashCode", "()I", false); + iv.invokevirtual(type.getInternalName(), "hashCode", "()I", false); } else if (type.getSort() == Type.BOOLEAN) { Label end = new Label(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index f26a661dae2..5b8e3c5af62 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -558,8 +558,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.store(2, OBJECT_TYPE); for (PropertyDescriptor propertyDescriptor : properties) { - KotlinType type = propertyDescriptor.getType(); - Type asmType = typeMapper.mapType(type); + Type asmType = typeMapper.mapType(propertyDescriptor); Type thisPropertyType = genPropertyOnStack(iv, context, propertyDescriptor, ImplementationBodyCodegen.this.classAsmType, 0); StackValue.coerce(thisPropertyType, asmType, iv); @@ -581,19 +580,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { value.put(Type.BOOLEAN_TYPE, iv); } else { - if (TypeUtils.isNullableType(type)) { + if (TypeUtils.isNullableType(propertyDescriptor.getType())) { StackValue value = genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType)); value.put(Type.BOOLEAN_TYPE, iv); } else { - ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); - Type owner = - !(classifier instanceof ClassDescriptor) || DescriptorUtils.isInterface(classifier) - ? AsmTypes.OBJECT_TYPE - : asmType; - iv.invokevirtual(owner.getInternalName(), "equals", - Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false); + iv.invokevirtual( + getEqualsOrHashCodeOwner(propertyDescriptor).getInternalName(), "equals", + Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false + ); } } iv.ifeq(ne); @@ -636,8 +632,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.ifnull(ifNull); } - genHashCode(mv, iv, asmType, state.getTarget(), - DescriptorUtils.isInterface(propertyDescriptor.getType().getConstructor().getDeclarationDescriptor())); + genHashCode(mv, iv, getEqualsOrHashCodeOwner(propertyDescriptor), state.getTarget()); if (ifNull != null) { Label end = new Label(); @@ -661,6 +656,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { FunctionCodegen.endVisit(mv, "hashCode", myClass); } + @NotNull + private Type getEqualsOrHashCodeOwner(@NotNull PropertyDescriptor descriptor) { + ClassifierDescriptor classifier = descriptor.getType().getConstructor().getDeclarationDescriptor(); + return !(classifier instanceof ClassDescriptor) || JvmCodegenUtil.isJvmInterface(classifier) + ? AsmTypes.OBJECT_TYPE + : typeMapper.mapType(descriptor); + } + @Override public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List properties) { MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function); diff --git a/compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt b/compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt deleted file mode 100644 index 7c4af80de04..00000000000 --- a/compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt +++ /dev/null @@ -1,10 +0,0 @@ -// IGNORE_BACKEND: JS_IR -interface A - -data class B(val a: T) - -fun box(): String { - val b1 = B(object : A {}) - val b2 = B(object : A {}) - return if (b1.equals(b2)) "Fail" else "OK" -} diff --git a/compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt b/compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt new file mode 100644 index 00000000000..2969cf1414a --- /dev/null +++ b/compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt @@ -0,0 +1,26 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME + +interface A + +data class B(val a: T) + +annotation class Anno + +@Anno +data class C(val a: Anno) + +fun box(): String { + val b1 = B(object : A {}) + val b2 = B(object : A {}) + if (b1.hashCode() == b2.hashCode()) return "Fail 1" + if (b1.equals(b2)) return "Fail 2" + + val anno = C::class.java.annotations.first() as Anno + val c1 = C(anno) + val c2 = C(anno) + if (c1.hashCode() != c2.hashCode()) return "Fail 3" + if (!c1.equals(c2)) return "Fail 4" + + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 63cebf08f45..72729fa2984 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7849,6 +7849,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt"); } + @TestMetadata("typeParameterWithInterfaceBound.kt") + public void testTypeParameterWithInterfaceBound() throws Exception { + runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt"); + } + @TestMetadata("unitComponent.kt") public void testUnitComponent() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt"); @@ -7953,11 +7958,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testSameinstance() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt"); } - - @TestMetadata("typeParameterWithInterfaceBound.kt") - public void testTypeParameterWithInterfaceBound() throws Exception { - runTest("compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt"); - } } @TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 52985e2d9fc..c01d08cb0c7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7849,6 +7849,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt"); } + @TestMetadata("typeParameterWithInterfaceBound.kt") + public void testTypeParameterWithInterfaceBound() throws Exception { + runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt"); + } + @TestMetadata("unitComponent.kt") public void testUnitComponent() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt"); @@ -7953,11 +7958,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testSameinstance() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt"); } - - @TestMetadata("typeParameterWithInterfaceBound.kt") - public void testTypeParameterWithInterfaceBound() throws Exception { - runTest("compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt"); - } } @TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e00f41281a2..1c145f63633 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7849,6 +7849,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt"); } + @TestMetadata("typeParameterWithInterfaceBound.kt") + public void testTypeParameterWithInterfaceBound() throws Exception { + runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithInterfaceBound.kt"); + } + @TestMetadata("unitComponent.kt") public void testUnitComponent() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt"); @@ -7953,11 +7958,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testSameinstance() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt"); } - - @TestMetadata("typeParameterWithInterfaceBound.kt") - public void testTypeParameterWithInterfaceBound() throws Exception { - runTest("compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt"); - } } @TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index 9a8c723e5c9..c4cc770afe5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -7651,11 +7651,6 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testSameinstance() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt"); } - - @TestMetadata("typeParameterWithInterfaceBound.kt") - public void testTypeParameterWithInterfaceBound() throws Exception { - runTest("compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt"); - } } @TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 4692c00eef9..e014bd04c67 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6541,11 +6541,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testSameinstance() throws Exception { runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt"); } - - @TestMetadata("typeParameterWithInterfaceBound.kt") - public void testTypeParameterWithInterfaceBound() throws Exception { - runTest("compiler/testData/codegen/box/dataClasses/equals/typeParameterWithInterfaceBound.kt"); - } } @TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")