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:
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
}
|
||||
+7
@@ -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"
|
||||
}
|
||||
|
||||
+37
@@ -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"
|
||||
}
|
||||
+27
@@ -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"
|
||||
}
|
||||
+9
@@ -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
|
||||
+66
@@ -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
|
||||
}
|
||||
+45
@@ -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);
|
||||
|
||||
+69
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user