Support of custom 'equals' and 'hashCode' in inline classes

'equals' from any made available for overriding in inline classes
'typed' equals made available for definition in inline classes
'typed' equals definition made compulsory if 'untyped' is overridden
'operator' keyword is allowed in 'typed' equals definition

^KT-24874: Fixed
This commit is contained in:
vladislav.grechko
2022-10-04 20:22:11 +02:00
committed by teamcity
parent 527e8dde27
commit e0c8142106
47 changed files with 684 additions and 53 deletions
@@ -0,0 +1,55 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
// TARGET_BACKEND: JVM_IR
interface I {
fun getVal(): Int
}
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC1(val x: Int) : I {
override fun getVal(): Int {
return x
}
fun equals(other: IC1): Boolean {
return x == other.x
}
override fun equals(other: Any?): Boolean {
if (other !is I) {
return false
}
return getVal() == other.getVal()
}
override fun hashCode(): Int {
return getVal()
}
}
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC2(val y: Int) : I {
override fun getVal(): Int {
return y * 10
}
fun equals(other: IC2): Boolean {
return y == other.y
}
override fun equals(other: Any?): Boolean {
if (other !is I) {
return false
}
return getVal() == other.getVal()
}
override fun hashCode(): Int {
return getVal()
}
}
fun box(): String = if (setOf(IC1(10), IC2(1)).size == 1) "OK" else "Fail"
@@ -0,0 +1,47 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
// TARGET_BACKEND: JVM_IR
import java.lang.AssertionError
import kotlin.math.abs
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC1(val x: Double) {
fun equals(other: IC1): Boolean {
return abs(x - other.x) < 0.5
}
}
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC2(val x: Int) {
override fun equals(other: Any?): Boolean {
if (other !is IC2) {
return false
}
return abs(x - other.x) < 2
}
}
fun box(): String {
val a1Typed: IC1 = IC1(1.0)
val b1Typed: IC1 = IC1(1.1)
val c1Typed: IC1 = IC1(5.0)
val a1Untyped: Any = a1Typed
val b1Untyped: Any = b1Typed
val c1Untyped: Any = c1Typed
val a2Typed: IC2 = IC2(1)
val b2Typed: IC2 = IC2(2)
val c2Typed: IC2 = IC2(5)
val a2Untyped: Any = a2Typed
val b2Untyped: Any = b2Typed
val c2Untyped: Any = c2Typed
if ((a1Typed == b1Typed) != (a1Untyped == b1Untyped)) throw AssertionError()
if ((a1Typed == c1Typed) != (a1Untyped == c1Untyped)) throw AssertionError()
if ((a2Typed == b2Typed) != (a2Untyped == b2Untyped)) throw AssertionError()
if ((a2Typed == c2Typed) != (a2Untyped == c2Untyped)) throw AssertionError()
return "OK"
}
@@ -0,0 +1,35 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
// TARGET_BACKEND: JVM_IR
import kotlin.math.abs
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC1(val value: Double) {
fun equals(other: IC1): Boolean {
return abs(value - other.value) < 0.1
}
}
interface I {
fun equals(param: IC2): Boolean
}
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC2(val value: Int) : I {
override fun equals(param: IC2): Boolean {
return abs(value - param.value) < 2
}
}
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC3(val value: Int) {
}
fun box() =
if (IC1(1.0) == IC1(1.05) && IC1(1.0) != IC1(1.2)
&& IC2(5) == IC2(6) && IC2(5) != IC2(7)
&& IC3(5) == IC3(5) && IC3(5) != IC3(6)
&& IC1(1.0) != Any()) "OK" else "Fail"
@@ -0,0 +1,22 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
// TARGET_BACKEND: JVM_IR
import kotlin.math.abs
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC(val x: Double) {
fun equals(other: IC): Boolean {
return abs(x - other.x) < 0.1
}
override fun hashCode(): Int {
return 0
}
}
fun box(): String {
val set = setOf(IC(1.0), IC(1.5), IC(1.501))
return if (set.size == 2) "OK" else "Fail"
}
@@ -0,0 +1,14 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
OPTIONAL_JVM_INLINE_ANNOTATION
value class A(val value: MyClass) {
override fun hashCode() = 42
}
class MyClass() {
override fun hashCode() = -1
}
fun box(): String = if (A(MyClass()).hashCode() == 42) "OK" else "Fail"
@@ -0,0 +1,23 @@
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +CustomEqualsInInlineClasses
// TARGET_BACKEND: JVM_IR
import kotlin.math.abs
OPTIONAL_JVM_INLINE_ANNOTATION
value class IC(val x: Int) {
override fun equals(other: Any?): Boolean {
if (other !is IC) {
return false
}
return abs(x - other.x) < 2
}
override fun hashCode() = 0
}
fun box(): String {
val set = setOf(IC(1), IC(2), IC(5))
return if (set.size == 2 && IC(1) == IC(1) && IC(1) == IC(2) && IC(1) != IC(5)) "OK" else "Fail"
}
@@ -1,7 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR status: not supported in JVM
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@@ -1,7 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR status: not supported in JVM
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses, +GenericInlineClassParameter