Fix bytecode for equals/hashCode of data classes once again
#KT-24790 Fixed
This commit is contained in:
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
|||||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
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.JvmClassName;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
|
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) {
|
if (type.getSort() == Type.ARRAY) {
|
||||||
Type elementType = correctElementType(type);
|
Type elementType = correctElementType(type);
|
||||||
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
||||||
@@ -525,7 +524,7 @@ public class AsmUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type.getSort() == Type.OBJECT) {
|
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) {
|
else if (type.getSort() == Type.BOOLEAN) {
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
|
|||||||
@@ -558,8 +558,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
iv.store(2, OBJECT_TYPE);
|
iv.store(2, OBJECT_TYPE);
|
||||||
|
|
||||||
for (PropertyDescriptor propertyDescriptor : properties) {
|
for (PropertyDescriptor propertyDescriptor : properties) {
|
||||||
KotlinType type = propertyDescriptor.getType();
|
Type asmType = typeMapper.mapType(propertyDescriptor);
|
||||||
Type asmType = typeMapper.mapType(type);
|
|
||||||
|
|
||||||
Type thisPropertyType = genPropertyOnStack(iv, context, propertyDescriptor, ImplementationBodyCodegen.this.classAsmType, 0);
|
Type thisPropertyType = genPropertyOnStack(iv, context, propertyDescriptor, ImplementationBodyCodegen.this.classAsmType, 0);
|
||||||
StackValue.coerce(thisPropertyType, asmType, iv);
|
StackValue.coerce(thisPropertyType, asmType, iv);
|
||||||
@@ -581,19 +580,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
value.put(Type.BOOLEAN_TYPE, iv);
|
value.put(Type.BOOLEAN_TYPE, iv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (TypeUtils.isNullableType(type)) {
|
if (TypeUtils.isNullableType(propertyDescriptor.getType())) {
|
||||||
StackValue value =
|
StackValue value =
|
||||||
genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType));
|
genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType));
|
||||||
value.put(Type.BOOLEAN_TYPE, iv);
|
value.put(Type.BOOLEAN_TYPE, iv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
|
iv.invokevirtual(
|
||||||
Type owner =
|
getEqualsOrHashCodeOwner(propertyDescriptor).getInternalName(), "equals",
|
||||||
!(classifier instanceof ClassDescriptor) || DescriptorUtils.isInterface(classifier)
|
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false
|
||||||
? AsmTypes.OBJECT_TYPE
|
);
|
||||||
: asmType;
|
|
||||||
iv.invokevirtual(owner.getInternalName(), "equals",
|
|
||||||
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iv.ifeq(ne);
|
iv.ifeq(ne);
|
||||||
@@ -636,8 +632,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
iv.ifnull(ifNull);
|
iv.ifnull(ifNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
genHashCode(mv, iv, asmType, state.getTarget(),
|
genHashCode(mv, iv, getEqualsOrHashCodeOwner(propertyDescriptor), state.getTarget());
|
||||||
DescriptorUtils.isInterface(propertyDescriptor.getType().getConstructor().getDeclarationDescriptor()));
|
|
||||||
|
|
||||||
if (ifNull != null) {
|
if (ifNull != null) {
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
@@ -661,6 +656,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
FunctionCodegen.endVisit(mv, "hashCode", myClass);
|
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
|
@Override
|
||||||
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties) {
|
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties) {
|
||||||
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
|
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
|
||||||
|
|||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
interface A
|
|
||||||
|
|
||||||
data class B<out T : A>(val a: T)
|
|
||||||
|
|
||||||
fun box(): String {
|
|
||||||
val b1 = B(object : A {})
|
|
||||||
val b2 = B(object : A {})
|
|
||||||
return if (b1.equals(b2)) "Fail" else "OK"
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface A
|
||||||
|
|
||||||
|
data class B<out T : A>(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"
|
||||||
|
}
|
||||||
Generated
+5
-5
@@ -7849,6 +7849,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt");
|
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")
|
@TestMetadata("unitComponent.kt")
|
||||||
public void testUnitComponent() throws Exception {
|
public void testUnitComponent() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
||||||
@@ -7953,11 +7958,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
public void testSameinstance() throws Exception {
|
public void testSameinstance() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")
|
||||||
|
|||||||
+5
-5
@@ -7849,6 +7849,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt");
|
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")
|
@TestMetadata("unitComponent.kt")
|
||||||
public void testUnitComponent() throws Exception {
|
public void testUnitComponent() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
||||||
@@ -7953,11 +7958,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
public void testSameinstance() throws Exception {
|
public void testSameinstance() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")
|
||||||
|
|||||||
+5
-5
@@ -7849,6 +7849,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/dataClasses/twoVarParams.kt");
|
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")
|
@TestMetadata("unitComponent.kt")
|
||||||
public void testUnitComponent() throws Exception {
|
public void testUnitComponent() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
runTest("compiler/testData/codegen/box/dataClasses/unitComponent.kt");
|
||||||
@@ -7953,11 +7958,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
public void testSameinstance() throws Exception {
|
public void testSameinstance() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")
|
||||||
|
|||||||
-5
@@ -7651,11 +7651,6 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
public void testSameinstance() throws Exception {
|
public void testSameinstance() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")
|
||||||
|
|||||||
-5
@@ -6541,11 +6541,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
public void testSameinstance() throws Exception {
|
public void testSameinstance() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/dataClasses/equals/sameinstance.kt");
|
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")
|
@TestMetadata("compiler/testData/codegen/box/dataClasses/hashCode")
|
||||||
|
|||||||
Reference in New Issue
Block a user