diff --git a/compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt b/compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt new file mode 100644 index 00000000000..070cde155b8 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/bound/equals/propertyAccessors.kt @@ -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" + } \ No newline at end of file diff --git a/compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt b/compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt new file mode 100644 index 00000000000..d29849655df --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/bound/equals/reflectionReference.kt @@ -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" + } \ No newline at end of file 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 64bb4126fb1..ada156ea026 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 @@ -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") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index e87ad42f1bf..ff44ead343f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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") diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt index 9c392ed2893..1cebfacf242 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -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(), KFunction, 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 = diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt index db06741b1c6..9ba9c13b5d5 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -23,7 +23,7 @@ import kotlin.reflect.KProperty0 internal open class KProperty0Impl : KProperty0, KPropertyImpl { 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 : KProperty0, KPropertyImpl { internal class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0 { 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) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt index f77551b9d84..41b984741fe 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt @@ -21,7 +21,7 @@ import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 internal open class KProperty1Impl : KProperty1, KPropertyImpl { - 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 : KProperty1, KPropertyImpl : KProperty1Impl, KMutableProperty1 { - 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) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt index e86ce9d65f1..dbed24829e2 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -21,7 +21,7 @@ import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KProperty2 internal open class KProperty2Impl : KProperty2, KPropertyImpl { - 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) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index b878e3fd3a0..57d47e6760d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -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 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(), KProperty { - 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 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 = diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index cef8d24ebbd..5e6133e8961 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -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 diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java index 3e4eca05669..478501da093 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java @@ -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) { diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java index 2bb4b8a0b30..d0f0d306f43 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java @@ -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()); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java index ad72643e5ec..15f21c3c4db 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java @@ -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()); 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 90b82af729c..ed73255d41e 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 @@ -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")