Equality comparison for bound callable references takes into account bound receiver.

Fixed KT-14939: use expected receiver type when generating receiver code in get/set methods for bound property references.
Otherwise we have VerifyError for bound receiver 'null' of type 'Nothing?', which is mapped to 'java.lang.Void'.

TODO: proper equality comparison for property accessors ('x::prop.getter', 'x::prop.setter').
This commit is contained in:
Dmitry Petrov
2016-11-23 14:03:23 +03:00
parent ce6cf6475c
commit 3dd0c9d1c7
28 changed files with 525 additions and 20 deletions
@@ -431,7 +431,7 @@ public class AsmUtil {
}
KotlinType captureReceiverType = closure.getCaptureReceiverType();
if (captureReceiverType != null) {
if (captureReceiverType != null && !CallableReferenceUtilKt.isForCallableReference(closure)) {
allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.codegen;
import com.google.common.collect.Lists;
import com.intellij.util.ArrayUtil;
import kotlin.Pair;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
@@ -78,6 +79,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
protected final CalculatedClosure closure;
private final Type asmType;
private final int visibilityFlag;
private final boolean shouldHaveBoundReferenceReceiver;
private Method constructor;
private Type superClassAsmType;
@@ -126,6 +128,8 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
this.closure = bindingContext.get(CLOSURE, classDescriptor);
assert closure != null : "Closure must be calculated for class: " + classDescriptor;
this.shouldHaveBoundReferenceReceiver = CallableReferenceUtilKt.isForBoundCallableReference(closure);
this.asmType = typeMapper.mapClass(classDescriptor);
visibilityFlag = AsmUtil.getVisibilityAccessFlagForClass(classDescriptor);
@@ -185,7 +189,6 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
protected void generateClosureBody() {
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), funDescriptor, strategy);
if (functionReferenceTarget != null) {
generateFunctionReferenceMethods(functionReferenceTarget);
}
@@ -415,23 +418,35 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
int k = 1;
for (FieldInfo fieldInfo : args) {
k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
Pair<Integer, Type> receiverIndexAndType =
CallableReferenceUtilKt.generateClosureFieldsInitializationFromParameters(iv, closure, args);
if (shouldHaveBoundReferenceReceiver && receiverIndexAndType == null) {
throw new AssertionError("No bound reference receiver in constructor parameters: " + args);
}
int boundReferenceReceiverParameterIndex = shouldHaveBoundReferenceReceiver ? receiverIndexAndType.getFirst() : -1;
Type boundReferenceReceiverType = shouldHaveBoundReferenceReceiver ? receiverIndexAndType.getSecond() : null;
iv.load(0, superClassAsmType);
String superClassConstructorDescriptor;
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) || superClassAsmType.equals(COROUTINE_IMPL)) {
int arity = funDescriptor.getValueParameters().size();
if (funDescriptor.getExtensionReceiverParameter() != null) arity++;
if (funDescriptor.getDispatchReceiverParameter() != null) arity++;
iv.iconst(arity);
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false);
if (shouldHaveBoundReferenceReceiver) {
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(iv, boundReferenceReceiverParameterIndex, boundReferenceReceiverType);
superClassConstructorDescriptor = "(ILjava/lang/Object;)V";
}
else {
superClassConstructorDescriptor = "(I)V";
}
}
else {
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
assert !shouldHaveBoundReferenceReceiver : "Unexpected bound reference with supertype " + superClassAsmType;
superClassConstructorDescriptor = "()V";
}
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", superClassConstructorDescriptor, false);
iv.visitInsn(RETURN);
@@ -187,7 +187,7 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
if (receiverType != null) {
ClassDescriptor classDescriptor = (ClassDescriptor) codegen.getContext().getParentContext().getContextDescriptor();
Type asmType = codegen.getState().getTypeMapper().mapClass(classDescriptor);
return CallableReferenceUtilKt.capturedReceiver(asmType, receiverType);
return CallableReferenceUtilKt.capturedBoundReferenceReceiver(asmType, receiverType);
}
// 0 is this (the callable reference class), 1 is the invoke() method's first parameter
@@ -126,13 +126,20 @@ class PropertyReferenceCodegen(
private fun generateConstructor() {
generateMethod("property reference init", 0, constructor) {
constructorArgs.fold(1) {
i, fieldInfo ->
AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, i, this)
}
val shouldHaveBoundReferenceReceiver = closure.isForBoundCallableReference()
val receiverIndexAndType = generateClosureFieldsInitializationFromParameters(closure, constructorArgs)
load(0, OBJECT_TYPE)
invokespecial(superAsmType.internalName, "<init>", "()V", false)
if (receiverIndexAndType == null) {
assert(!shouldHaveBoundReferenceReceiver) { "No bound reference receiver in constructor parameters: $constructorArgs" }
load(0, OBJECT_TYPE)
invokespecial(superAsmType.internalName, "<init>", "()V", false)
}
else {
val (receiverIndex, receiverType) = receiverIndexAndType
load(0, OBJECT_TYPE)
loadBoundReferenceReceiverParameter(receiverIndex, receiverType)
invokespecial(superAsmType.internalName, "<init>", "(Ljava/lang/Object;)V", false)
}
}
}
@@ -248,7 +255,10 @@ class PropertyReferenceCodegen(
}
if (receiverType != null) {
capturedReceiver(asmType, receiverType).put(receiverType, v)
val expectedReceiver = target.dispatchReceiverParameter ?: target.extensionReceiverParameter ?:
throw AssertionError("receiverType: $receiverType; no dispatch or extension receiver: $target")
val expectedReceiverType = typeMapper.mapType(expectedReceiver.type)
capturedBoundReferenceReceiver(asmType, expectedReceiverType).put(expectedReceiverType, v)
}
else {
val receivers = originalFunctionDesc.valueParameters.dropLast(if (isGetter) 0 else 1)
@@ -29,6 +29,9 @@ import java.util.List;
import java.util.Map;
public interface CalculatedClosure {
@NotNull
ClassDescriptor getClosureClass();
@Nullable
ClassDescriptor getCaptureThis();
@@ -29,6 +29,7 @@ import java.util.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember;
public final class MutableClosure implements CalculatedClosure {
private final ClassDescriptor closureClass;
private final ClassDescriptor enclosingClass;
private final CallableDescriptor enclosingFunWithReceiverDescriptor;
@@ -42,6 +43,7 @@ public final class MutableClosure implements CalculatedClosure {
private boolean isCoroutine;
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
this.closureClass = classDescriptor;
this.enclosingClass = enclosingClass;
this.enclosingFunWithReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
}
@@ -58,6 +60,12 @@ public final class MutableClosure implements CalculatedClosure {
return null;
}
@NotNull
@Override
public ClassDescriptor getClosureClass() {
return closureClass;
}
@Nullable
public ClassDescriptor getEnclosingClass() {
return enclosingClass;
@@ -16,8 +16,58 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
fun capturedReceiver(ownerType: Type, capturedReceiverType: Type): StackValue.Field {
return StackValue.field(capturedReceiverType, ownerType, AsmUtil.CAPTURED_RECEIVER_FIELD, /* isStatic = */ false, StackValue.LOCAL_0)
fun capturedBoundReferenceReceiver(ownerType: Type, expectedReceiverType: Type): StackValue =
StackValue.operation(expectedReceiverType) { iv ->
iv.load(0, ownerType)
iv.getfield(ownerType.internalName, AsmUtil.CAPTURED_RECEIVER_FIELD, AsmTypes.OBJECT_TYPE.descriptor)
StackValue.coerce(AsmTypes.OBJECT_TYPE, expectedReceiverType, iv)
}
fun ClassDescriptor.isSyntheticClassForCallableReference(): Boolean =
this is SyntheticClassDescriptorForLambda &&
(this.source as? KotlinSourceElement)?.psi is KtCallableReferenceExpression
fun CalculatedClosure.isForCallableReference(): Boolean =
closureClass.isSyntheticClassForCallableReference()
fun CalculatedClosure.isForBoundCallableReference(): Boolean =
isForCallableReference() && captureReceiverType != null
fun InstructionAdapter.loadBoundReferenceReceiverParameter(index: Int, type: Type) {
load(index, type)
StackValue.coerce(type, AsmTypes.OBJECT_TYPE, this)
}
fun CalculatedClosure.isBoundReferenceReceiverField(fieldInfo: FieldInfo): Boolean =
isForBoundCallableReference() &&
fieldInfo.fieldName == AsmUtil.CAPTURED_RECEIVER_FIELD
fun InstructionAdapter.generateClosureFieldsInitializationFromParameters(closure: CalculatedClosure, args: List<FieldInfo>): Pair<Int, Type>? {
var k = 1
var boundReferenceReceiverParameterIndex = -1
var boundReferenceReceiverType: Type? = null
for (fieldInfo in args) {
if (closure.isBoundReferenceReceiverField(fieldInfo)) {
boundReferenceReceiverParameterIndex = k
boundReferenceReceiverType = fieldInfo.fieldType
k += fieldInfo.fieldType.size
continue
}
k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, this)
}
return when {
boundReferenceReceiverType != null ->
Pair(boundReferenceReceiverParameterIndex, boundReferenceReceiverType)
else ->
null
}
}
@@ -0,0 +1,7 @@
class A {
companion object {
fun ok() = "OK"
}
}
fun box() = (A.Companion::ok)()
@@ -9,8 +9,11 @@ enum class E {
fun box(): String {
val f = E.A::foo
val ef = E::foo
if (f() != "A") return "Fail 1: ${f()}"
if (f != E.B::foo) return "Fail 2"
if (f == E.B::foo) return "Fail 2"
if (ef != E::foo) return "Fail 3"
return "OK"
}
@@ -0,0 +1,37 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// See https://youtrack.jetbrains.com/issue/KT-14938
// WITH_REFLECT
class A
val a = A()
val aa = A()
fun A?.foo() {}
var A?.bar: Int
get() = 42
set(value) {}
val aFoo = a::foo
val A_foo = A::foo
val nullFoo = null::foo
val aBar = a::bar
val A_bar = A::bar
val nullBar = null::bar
fun box(): String =
when {
nullFoo != null::foo -> "Bound extension refs with same receiver SHOULD be equal"
nullFoo == aFoo -> "Bound extension refs with different receivers SHOULD NOT be equal"
nullFoo == A_foo -> "Bound extension ref with receiver 'null' SHOULD NOT be equal to free ref"
nullBar != null::bar -> "Bound extension property refs with same receiver SHOULD be equal"
nullBar == aBar -> "Bound extension property refs with different receivers SHOULD NOT be equal"
nullBar == A_bar -> "Bound extension property ref with receiver 'null' SHOULD NOT be equal to free property ref"
else -> "OK"
}
@@ -0,0 +1,27 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
package test
class A {
fun foo() {}
fun bar() {}
}
val a = A()
val aa = A()
val aFoo = a::foo
val aBar = a::bar
val aaFoo = aa::foo
val A_foo = A::foo
fun box(): String =
when {
aFoo != a::foo -> "Bound refs with same receiver SHOULD be equal"
aFoo == aBar -> "Bound refs to different members SHOULD NOT be equal"
aFoo == aaFoo -> "Bound refs with different receiver SHOULD NOT be equal"
aFoo == A_foo -> "Bound ref SHOULD NOT be equal to free ref"
else -> "OK"
}
@@ -0,0 +1,9 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// See https://youtrack.jetbrains.com/issue/KT-14939
val String?.ok: String
get() = "OK"
fun box() = (null::ok).get()
@@ -0,0 +1,5 @@
object Singleton {
fun ok() = "OK"
}
fun box() = (Singleton::ok)()
@@ -0,0 +1,29 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun Boolean.foo() = 1
fun Byte.foo() = 2
fun Short.foo() = 3
fun Int.foo() = 4
fun Long.foo() = 5
fun Char.foo() = 6
fun Float.foo() = 7
fun Double.foo() = 8
fun testRef(name: String, f: () -> Int, expected: Int) {
val actual = f()
if (actual != expected) throw AssertionError("$name: $actual != $expected")
}
fun box(): String {
testRef("Boolean", true::foo, 1)
testRef("Byte", 1.toByte()::foo, 2)
testRef("Short", 1.toShort()::foo, 3)
testRef("Int", 1::foo, 4)
testRef("Long", 1L::foo, 5)
testRef("Char", '1'::foo, 6)
testRef("Float", 1.0F::foo, 7)
testRef("Double", 1.0::foo, 8)
return "OK"
}
@@ -0,0 +1,9 @@
class A {
fun foo() {}
val bar = 42
}
val aFoo = A()::foo
val aBar = A()::bar
val A_foo = A::foo
val A_bar = A::bar
@@ -0,0 +1,66 @@
@kotlin.Metadata
public final class A {
private final field bar: int
public method <init>(): void
public final method foo(): void
public final method getBar(): int
}
@kotlin.Metadata
final class NoReceiverInCallableReferenceClassesKt$A_bar$1 {
public final static field INSTANCE: kotlin.reflect.KProperty1
static method <clinit>(): void
method <init>(): void
public @org.jetbrains.annotations.Nullable method get(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
public method getName(): java.lang.String
public method getOwner(): kotlin.reflect.KDeclarationContainer
public method getSignature(): java.lang.String
}
@kotlin.Metadata
final class NoReceiverInCallableReferenceClassesKt$A_foo$1 {
public final static field INSTANCE: NoReceiverInCallableReferenceClassesKt$A_foo$1
inner class NoReceiverInCallableReferenceClassesKt$A_foo$1
static method <clinit>(): void
method <init>(): void
public final method getName(): java.lang.String
public final method getOwner(): kotlin.reflect.KDeclarationContainer
public final method getSignature(): java.lang.String
public final method invoke(@org.jetbrains.annotations.NotNull p0: A): void
public synthetic method invoke(p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
final class NoReceiverInCallableReferenceClassesKt$aBar$1 {
method <init>(p0: A): void
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
public method getName(): java.lang.String
public method getOwner(): kotlin.reflect.KDeclarationContainer
public method getSignature(): java.lang.String
}
@kotlin.Metadata
final class NoReceiverInCallableReferenceClassesKt$aFoo$1 {
inner class NoReceiverInCallableReferenceClassesKt$aFoo$1
method <init>(p0: A): void
public final method getName(): java.lang.String
public final method getOwner(): kotlin.reflect.KDeclarationContainer
public final method getSignature(): java.lang.String
public synthetic method invoke(): java.lang.Object
public final method invoke(): void
}
@kotlin.Metadata
public final class NoReceiverInCallableReferenceClassesKt {
private final static @org.jetbrains.annotations.NotNull field A_bar: kotlin.reflect.KProperty1
private final static @org.jetbrains.annotations.NotNull field A_foo: kotlin.reflect.KFunction
private final static @org.jetbrains.annotations.NotNull field aBar: kotlin.reflect.KProperty0
private final static @org.jetbrains.annotations.NotNull field aFoo: kotlin.reflect.KFunction
inner class NoReceiverInCallableReferenceClassesKt$A_foo$1
inner class NoReceiverInCallableReferenceClassesKt$aFoo$1
static method <clinit>(): void
public final static @org.jetbrains.annotations.NotNull method getABar(): kotlin.reflect.KProperty0
public final static @org.jetbrains.annotations.NotNull method getAFoo(): kotlin.reflect.KFunction
public final static @org.jetbrains.annotations.NotNull method getA_bar(): kotlin.reflect.KProperty1
public final static @org.jetbrains.annotations.NotNull method getA_foo(): kotlin.reflect.KFunction
}
@@ -1501,6 +1501,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("companionObjectReceiver.kt")
public void testCompanionObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -1519,6 +1525,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
doTest(fileName);
}
@TestMetadata("objectReceiver.kt")
public void testObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt");
doTest(fileName);
}
@TestMetadata("primitiveReceiver.kt")
public void testPrimitiveReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt");
doTest(fileName);
}
@TestMetadata("simpleFunction.kt")
public void testSimpleFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt");
@@ -1537,6 +1561,27 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Equals extends AbstractIrBlackBoxCodegenTest {
public void testAllFilesPresentInEquals() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound/equals"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("nullableReceiverInEquals.kt")
public void testNullableReceiverInEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/nullableReceiverInEquals.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("compiler/testData/codegen/box/callableReference/bound/inline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1501,6 +1501,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("companionObjectReceiver.kt")
public void testCompanionObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -1519,6 +1525,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
doTest(fileName);
}
@TestMetadata("objectReceiver.kt")
public void testObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt");
doTest(fileName);
}
@TestMetadata("primitiveReceiver.kt")
public void testPrimitiveReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt");
doTest(fileName);
}
@TestMetadata("simpleFunction.kt")
public void testSimpleFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt");
@@ -1537,6 +1561,27 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Equals extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInEquals() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound/equals"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("nullableReceiverInEquals.kt")
public void testNullableReceiverInEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/nullableReceiverInEquals.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("compiler/testData/codegen/box/callableReference/bound/inline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -90,6 +90,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
doTest(fileName);
}
@TestMetadata("noReceiverInCallableReferenceClasses.kt")
public void testNoReceiverInCallableReferenceClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/noReceiverInCallableReferenceClasses.kt");
doTest(fileName);
}
@TestMetadata("noRemoveAtInReadOnly.kt")
public void testNoRemoveAtInReadOnly() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/noRemoveAtInReadOnly.kt");
@@ -39,6 +39,17 @@ public abstract class CallableReference implements KCallable {
// objects are written to it. The latter is guaranteed because both KFunctionImpl and KPropertyImpl have at least one final field.
private KCallable reflected;
protected final Object receiver$0;
private static final Object NO_RECEIVER = new Object();
public CallableReference() {
this(NO_RECEIVER);
}
protected CallableReference(Object receiver$0) {
this.receiver$0 = receiver$0;
}
protected abstract KCallable computeReflected();
public KCallable compute() {
@@ -26,6 +26,11 @@ public class FunctionReference extends CallableReference implements FunctionImpl
this.arity = arity;
}
public FunctionReference(int arity, Object receiver) {
super(receiver);
this.arity = arity;
}
@Override
public int getArity() {
return arity;
@@ -71,9 +76,11 @@ public class FunctionReference extends CallableReference implements FunctionImpl
if (obj == this) return true;
if (obj instanceof FunctionReference) {
FunctionReference other = (FunctionReference) obj;
return getOwner().equals(other.getOwner()) &&
getName().equals(other.getName()) &&
getSignature().equals(other.getSignature());
getSignature().equals(other.getSignature()) &&
Intrinsics.areEqual(receiver$0, other.receiver$0);
}
if (obj instanceof KFunction) {
return obj.equals(compute());
@@ -19,4 +19,10 @@ package kotlin.jvm.internal;
import kotlin.reflect.KMutableProperty;
public abstract class MutablePropertyReference extends PropertyReference implements KMutableProperty {
public MutablePropertyReference() {
}
public MutablePropertyReference(Object receiver$0) {
super(receiver$0);
}
}
@@ -21,6 +21,13 @@ import kotlin.reflect.KMutableProperty0;
import kotlin.reflect.KProperty0;
public abstract class MutablePropertyReference0 extends MutablePropertyReference implements KMutableProperty0 {
public MutablePropertyReference0() {
}
public MutablePropertyReference0(Object receiver$0) {
super(receiver$0);
}
@Override
protected KCallable computeReflected() {
return Reflection.mutableProperty0(this);
@@ -21,6 +21,13 @@ import kotlin.reflect.KMutableProperty1;
import kotlin.reflect.KProperty1;
public abstract class MutablePropertyReference1 extends MutablePropertyReference implements KMutableProperty1 {
public MutablePropertyReference1() {
}
public MutablePropertyReference1(Object receiver$0) {
super(receiver$0);
}
@Override
protected KCallable computeReflected() {
return Reflection.mutableProperty1(this);
@@ -20,6 +20,14 @@ import kotlin.reflect.KCallable;
import kotlin.reflect.KProperty;
public abstract class PropertyReference extends CallableReference implements KProperty {
public PropertyReference() {
super();
}
public PropertyReference(Object receiver$0) {
super(receiver$0);
}
@Override
protected KProperty getReflected() {
return (KProperty) super.getReflected();
@@ -42,7 +50,8 @@ public abstract class PropertyReference extends CallableReference implements KPr
PropertyReference other = (PropertyReference) obj;
return getOwner().equals(other.getOwner()) &&
getName().equals(other.getName()) &&
getSignature().equals(other.getSignature());
getSignature().equals(other.getSignature()) &&
Intrinsics.areEqual(receiver$0, other.receiver$0);
}
if (obj instanceof KProperty) {
return obj.equals(compute());
@@ -20,6 +20,14 @@ import kotlin.reflect.KCallable;
import kotlin.reflect.KProperty0;
public abstract class PropertyReference0 extends PropertyReference implements KProperty0 {
public PropertyReference0() {
super();
}
public PropertyReference0(Object receiver$0) {
super(receiver$0);
}
@Override
protected KCallable computeReflected() {
return Reflection.property0(this);
@@ -20,6 +20,13 @@ import kotlin.reflect.KCallable;
import kotlin.reflect.KProperty1;
public abstract class PropertyReference1 extends PropertyReference implements KProperty1 {
public PropertyReference1() {
}
public PropertyReference1(Object receiver$0) {
super(receiver$0);
}
@Override
protected KCallable computeReflected() {
return Reflection.property1(this);
@@ -1874,6 +1874,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("companionObjectReceiver.kt")
public void testCompanionObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -1910,6 +1916,36 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.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("objectReceiver.kt")
public void testObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt");
doTest(fileName);
}
@TestMetadata("primitiveReceiver.kt")
public void testPrimitiveReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.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("simpleFunction.kt")
public void testSimpleFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt");
@@ -1946,6 +1982,39 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Equals extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInEquals() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/callableReference/bound/equals"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("nullableReceiverInEquals.kt")
public void testNullableReceiverInEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/equals/nullableReceiverInEquals.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");
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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)