Revert changes to data class equals/hashCode (KT-12330)

This looked like a small and useful change, but caused so many issues
(KT-24474, KT-24790, 30b9caea, and another unreported one -- see the
test update in this commit) that it didn't pay off after all. The
optimization is not that critical for now, as it's only relevant for
data classes where component types have trivial equals/hashCode
implementation, which is not very often

 #KT-12330 Declined
This commit is contained in:
Alexander Udalov
2018-06-18 12:23:28 +02:00
parent 21ca06dace
commit 863639c9ab
8 changed files with 21 additions and 60 deletions
@@ -524,7 +524,7 @@ public class AsmUtil {
}
}
else if (type.getSort() == Type.OBJECT) {
iv.invokevirtual(type.getInternalName(), "hashCode", "()I", false);
iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
}
else if (type.getSort() == Type.BOOLEAN) {
Label end = new Label();
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
@@ -52,7 +51,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.org.objectweb.asm.FieldVisitor;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -575,23 +573,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.ifne(ne);
}
else {
if (isPrimitive(asmType)) {
StackValue value = StackValue.cmp(KtTokens.EQEQ, asmType, StackValue.onStack(asmType), StackValue.onStack(asmType));
value.put(Type.BOOLEAN_TYPE, iv);
}
else {
if (TypeUtils.isNullableType(propertyDescriptor.getType())) {
StackValue value =
genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType));
value.put(Type.BOOLEAN_TYPE, iv);
}
else {
iv.invokevirtual(
getEqualsOrHashCodeOwner(propertyDescriptor).getInternalName(), "equals",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false
);
}
}
StackValue value =
genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType));
value.put(Type.BOOLEAN_TYPE, iv);
iv.ifeq(ne);
}
}
@@ -632,7 +616,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.ifnull(ifNull);
}
genHashCode(mv, iv, getEqualsOrHashCodeOwner(propertyDescriptor), state.getTarget());
genHashCode(mv, iv, asmType, state.getTarget());
if (ifNull != null) {
Label end = new Label();
@@ -656,14 +640,6 @@ 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<? extends PropertyDescriptor> properties) {
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
@@ -10,6 +10,8 @@ annotation class Anno
@Anno
data class C(val a: Anno)
data class D<T : Int>(val t: T)
fun box(): String {
val b1 = B(object : A {})
val b2 = B(object : A {})
@@ -22,5 +24,10 @@ fun box(): String {
if (c1.hashCode() != c2.hashCode()) return "Fail 3"
if (!c1.equals(c2)) return "Fail 4"
val d1 = D<Int>(1)
val d2 = D<Int>(2)
if (d1.hashCode() == d2.hashCode()) return "Fail 5"
if (d1.equals(d2)) return "Fail 6"
return "OK"
}
@@ -1,4 +0,0 @@
data class D(val x: List<String>)
// 1 INVOKEVIRTUAL java/lang/Object.hashCode
// 1 INVOKEVIRTUAL java/lang/Object.equals
@@ -7849,9 +7849,9 @@ 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("typeParameterWithNonTrivialBound.kt")
public void testTypeParameterWithNonTrivialBound() throws Exception {
runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithNonTrivialBound.kt");
}
@TestMetadata("unitComponent.kt")
@@ -7849,9 +7849,9 @@ 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("typeParameterWithNonTrivialBound.kt")
public void testTypeParameterWithNonTrivialBound() throws Exception {
runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithNonTrivialBound.kt");
}
@TestMetadata("unitComponent.kt")
@@ -1243,24 +1243,6 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/dataClasses")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DataClasses extends AbstractBytecodeTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInDataClasses() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/dataClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt12330.kt")
public void testKt12330() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -7849,9 +7849,9 @@ 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("typeParameterWithNonTrivialBound.kt")
public void testTypeParameterWithNonTrivialBound() throws Exception {
runTest("compiler/testData/codegen/box/dataClasses/typeParameterWithNonTrivialBound.kt");
}
@TestMetadata("unitComponent.kt")