Proper equality comparison for bound callable references represented as reflection objects
(including references to property accessors).
This commit is contained in:
+32
@@ -0,0 +1,32 @@
|
||||
// TODO: investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
class C {
|
||||
var prop = 42
|
||||
}
|
||||
|
||||
val C_propReflect = C::class.memberProperties.find { it.name == "prop" } as? KMutableProperty1 ?: throw AssertionError()
|
||||
val C_prop = C::prop
|
||||
val cProp = C()::prop
|
||||
|
||||
fun box() =
|
||||
when {
|
||||
C_prop.getter != C_prop.getter -> "C_prop.getter != C_prop.getter"
|
||||
C_propReflect.getter != C_propReflect.getter -> "C_propReflect.getter != C_propReflect.getter"
|
||||
cProp.getter != cProp.getter -> "cProp.getter != cProp.getter"
|
||||
|
||||
cProp.getter == C_prop.getter -> "cProp.getter == C_prop.getter"
|
||||
C_prop.getter == cProp.getter -> "C_prop.getter == cProp.getter"
|
||||
cProp.getter == C_propReflect.getter -> "cProp.getter == C_propReflect.getter"
|
||||
C_propReflect.getter == cProp.getter -> "C_propReflect.getter == cProp.getter"
|
||||
|
||||
// TODO https://youtrack.jetbrains.com/issue/KT-13490
|
||||
// cProp.getter != C()::prop.getter -> "cProp.getter != C()::prop.getter"
|
||||
// cProp.setter != C()::prop.setter -> "cProp.setter != C()::prop.setter"
|
||||
|
||||
else -> "OK"
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// TODO: investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
class C {
|
||||
fun foo() {}
|
||||
val bar = 42
|
||||
}
|
||||
|
||||
val C_fooReflect = C::class.functions.find { it.name == "foo" }!!
|
||||
val C_foo = C::foo
|
||||
val cFoo = C()::foo
|
||||
|
||||
val C_barReflect = C::class.memberProperties.find { it.name == "bar" }!!
|
||||
val C_bar = C::bar
|
||||
val cBar= C()::bar
|
||||
|
||||
val Any.className: String
|
||||
get() = this::class.qualifiedName!!
|
||||
|
||||
fun box(): String =
|
||||
when {
|
||||
C_fooReflect != C_foo -> "C_fooReflect != C_foo, ${C_fooReflect.className}"
|
||||
C_foo != C_fooReflect -> "C_foo != C_fooReflect, ${C_foo.className}"
|
||||
C_fooReflect == cFoo -> "C_fooReflect == cFoo, ${C_fooReflect.className}"
|
||||
cFoo == C_fooReflect -> "cFoo == C_fooReflect, ${cFoo.className}"
|
||||
C_barReflect != C_bar -> "C_barReflect != C_bar, ${C_barReflect.className}"
|
||||
C_bar != C_barReflect -> "C_bar != C_barReflect, ${C_bar.className}"
|
||||
C_barReflect == cBar -> "C_barReflect == cBar, ${C_barReflect.className}"
|
||||
cBar == C_barReflect -> "cBar == C_barReflect, ${cBar.className}"
|
||||
else -> "OK"
|
||||
}
|
||||
+12
@@ -1575,11 +1575,23 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAccessors.kt")
|
||||
public void testPropertyAccessors() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("receiverInEquals.kt")
|
||||
public void testReceiverInEquals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/receiverInEquals.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reflectionReference.kt")
|
||||
public void testReflectionReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/inline")
|
||||
|
||||
@@ -1575,11 +1575,23 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAccessors.kt")
|
||||
public void testPropertyAccessors() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("receiverInEquals.kt")
|
||||
public void testReceiverInEquals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/receiverInEquals.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reflectionReference.kt")
|
||||
public void testReflectionReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/inline")
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.jvm.internal.CallableReference
|
||||
import kotlin.jvm.internal.FunctionImpl
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
@@ -36,12 +37,17 @@ internal class KFunctionImpl private constructor(
|
||||
override val container: KDeclarationContainerImpl,
|
||||
name: String,
|
||||
private val signature: String,
|
||||
descriptorInitialValue: FunctionDescriptor?
|
||||
descriptorInitialValue: FunctionDescriptor?,
|
||||
private val boundReceiver: Any? = CallableReference.NO_RECEIVER
|
||||
) : KCallableImpl<Any?>(), KFunction<Any?>, FunctionImpl, FunctionWithAllInvokes {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : this(container, name, signature, null)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?)
|
||||
: this(container, name, signature, null, boundReceiver)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: FunctionDescriptor) : this(
|
||||
container, descriptor.name.asString(), RuntimeTypeMapper.mapSignature(descriptor).asString(), descriptor
|
||||
container,
|
||||
descriptor.name.asString(),
|
||||
RuntimeTypeMapper.mapSignature(descriptor).asString(),
|
||||
descriptor
|
||||
)
|
||||
|
||||
override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) {
|
||||
@@ -140,7 +146,7 @@ internal class KFunctionImpl private constructor(
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
val that = other.asKFunctionImpl() ?: return false
|
||||
return container == that.container && name == that.name && signature == that.signature
|
||||
return container == that.container && name == that.name && signature == that.signature && boundReceiver == that.boundReceiver
|
||||
}
|
||||
|
||||
override fun hashCode(): Int =
|
||||
|
||||
@@ -23,7 +23,7 @@ import kotlin.reflect.KProperty0
|
||||
internal open class KProperty0Impl<out R> : KProperty0<R>, KPropertyImpl<R> {
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : super(container, name, signature, boundReceiver)
|
||||
|
||||
private val getter_ = ReflectProperties.lazy { Getter(this) }
|
||||
|
||||
@@ -41,7 +41,7 @@ internal open class KProperty0Impl<out R> : KProperty0<R>, KPropertyImpl<R> {
|
||||
internal class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R> {
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : super(container, name, signature, boundReceiver)
|
||||
|
||||
private val setter_ = ReflectProperties.lazy { Setter(this) }
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
internal open class KProperty1Impl<T, out R> : KProperty1<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : super(container, name, signature, boundReceiver)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -39,7 +39,7 @@ internal open class KProperty1Impl<T, out R> : KProperty1<T, R>, KPropertyImpl<R
|
||||
}
|
||||
|
||||
internal class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : super(container, name, signature, boundReceiver)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.reflect.KProperty2
|
||||
|
||||
internal open class KProperty2Impl<D, E, out R> : KProperty2<D, E, R>, KPropertyImpl<R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, null)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.jvm.internal.CallableReference
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KMutableProperty
|
||||
import kotlin.reflect.KProperty
|
||||
@@ -35,10 +36,11 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
override val container: KDeclarationContainerImpl,
|
||||
override val name: String,
|
||||
val signature: String,
|
||||
descriptorInitialValue: PropertyDescriptor?
|
||||
descriptorInitialValue: PropertyDescriptor?,
|
||||
private val boundReceiver: Any? = CallableReference.NO_RECEIVER
|
||||
) : KCallableImpl<R>(), KProperty<R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : this(
|
||||
container, name, signature, null
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this(
|
||||
container, name, signature, null, boundReceiver
|
||||
)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : this(
|
||||
@@ -95,7 +97,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
val that = other.asKPropertyImpl() ?: return false
|
||||
return container == that.container && name == that.name && signature == that.signature
|
||||
return container == that.container && name == that.name && signature == that.signature && boundReceiver == that.boundReceiver
|
||||
}
|
||||
|
||||
override fun hashCode(): Int =
|
||||
|
||||
@@ -66,29 +66,29 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
|
||||
@Override
|
||||
public KFunction function(FunctionReference f) {
|
||||
return new KFunctionImpl(getOwner(f), f.getName(), f.getSignature());
|
||||
return new KFunctionImpl(getOwner(f), f.getName(), f.getSignature(), f.getBoundReceiver());
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
@Override
|
||||
public KProperty0 property0(PropertyReference0 p) {
|
||||
return new KProperty0Impl(getOwner(p), p.getName(), p.getSignature());
|
||||
return new KProperty0Impl(getOwner(p), p.getName(), p.getSignature(), p.getBoundReceiver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
|
||||
return new KMutableProperty0Impl(getOwner(p), p.getName(), p.getSignature());
|
||||
return new KMutableProperty0Impl(getOwner(p), p.getName(), p.getSignature(), p.getBoundReceiver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty1 property1(PropertyReference1 p) {
|
||||
return new KProperty1Impl(getOwner(p), p.getName(), p.getSignature());
|
||||
return new KProperty1Impl(getOwner(p), p.getName(), p.getSignature(), p.getBoundReceiver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
|
||||
return new KMutableProperty1Impl(getOwner(p), p.getName(), p.getSignature());
|
||||
return new KMutableProperty1Impl(getOwner(p), p.getName(), p.getSignature(), p.getBoundReceiver());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract class CallableReference implements KCallable {
|
||||
private KCallable reflected;
|
||||
|
||||
protected final Object receiver$0;
|
||||
private static final Object NO_RECEIVER = new Object();
|
||||
public static final Object NO_RECEIVER = new Object();
|
||||
|
||||
public CallableReference() {
|
||||
this(NO_RECEIVER);
|
||||
@@ -52,6 +52,10 @@ public abstract class CallableReference implements KCallable {
|
||||
|
||||
protected abstract KCallable computeReflected();
|
||||
|
||||
public Object getBoundReceiver() {
|
||||
return receiver$0;
|
||||
}
|
||||
|
||||
public KCallable compute() {
|
||||
KCallable result = reflected;
|
||||
if (result == null) {
|
||||
|
||||
@@ -80,7 +80,7 @@ public class FunctionReference extends CallableReference implements FunctionImpl
|
||||
return getOwner().equals(other.getOwner()) &&
|
||||
getName().equals(other.getName()) &&
|
||||
getSignature().equals(other.getSignature()) &&
|
||||
Intrinsics.areEqual(receiver$0, other.receiver$0);
|
||||
Intrinsics.areEqual(getBoundReceiver(), other.getBoundReceiver());
|
||||
}
|
||||
if (obj instanceof KFunction) {
|
||||
return obj.equals(compute());
|
||||
|
||||
@@ -51,7 +51,7 @@ public abstract class PropertyReference extends CallableReference implements KPr
|
||||
return getOwner().equals(other.getOwner()) &&
|
||||
getName().equals(other.getName()) &&
|
||||
getSignature().equals(other.getSignature()) &&
|
||||
Intrinsics.areEqual(receiver$0, other.receiver$0);
|
||||
Intrinsics.areEqual(getBoundReceiver(), other.getBoundReceiver());
|
||||
}
|
||||
if (obj instanceof KProperty) {
|
||||
return obj.equals(compute());
|
||||
|
||||
+24
@@ -2002,6 +2002,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAccessors.kt")
|
||||
public void testPropertyAccessors() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("receiverInEquals.kt")
|
||||
public void testReceiverInEquals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/receiverInEquals.kt");
|
||||
@@ -2013,6 +2025,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("reflectionReference.kt")
|
||||
public void testReflectionReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/inline")
|
||||
|
||||
Reference in New Issue
Block a user