diff --git a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt index ddf856c54da..61cdc700fcf 100644 --- a/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt +++ b/compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt @@ -1,3 +1,6 @@ +// TODO investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + class A { companion object { fun ok() = "OK" diff --git a/compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt b/compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt index a03203792d5..417ca7ad143 100644 --- a/compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt +++ b/compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt @@ -1,3 +1,6 @@ +// TODO investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + object Singleton { fun ok() = "OK" } diff --git a/compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt b/compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt index fec2d79a7e1..2773e0cdcd1 100644 --- a/compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt +++ b/compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt @@ -1,6 +1,3 @@ -// 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 diff --git a/compiler/testData/codegen/box/delegatedProperty/stackOverflowOnCallFromGetValue.kt b/compiler/testData/codegen/box/delegatedProperty/stackOverflowOnCallFromGetValue.kt index eef227fbae5..9f06958fede 100644 --- a/compiler/testData/codegen/box/delegatedProperty/stackOverflowOnCallFromGetValue.kt +++ b/compiler/testData/codegen/box/delegatedProperty/stackOverflowOnCallFromGetValue.kt @@ -33,8 +33,9 @@ fun check(lambda: () -> Unit) { lambda() } catch (e: Throwable) { if (e !is InvocationTargetException && e !is StackOverflowError) { - throw AssertionError("The current implementation uses reflection to get the value of the property," + - "so either InvocationTargetException or StackOverflowError should have happened, but was: ${e}") + throw RuntimeException("The current implementation uses reflection to get the value of the property," + + "so either InvocationTargetException or StackOverflowError should have happened", + e) } return } diff --git a/compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt new file mode 100644 index 00000000000..7bc2f35ee6f --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt @@ -0,0 +1,53 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +class Host { + companion object { + val x = 1 + var y = 2 + + val xx: Int + get() = x + + var yy: Int + get() = y + set(value) { y = value } + } +} + +val c_x = Host.Companion::x +val c_xx = Host.Companion::xx +val c_y = Host.Companion::y +val c_yy = Host.Companion::yy + +fun box(): String { + assertEquals(1, c_x.getter()) + assertEquals(1, c_x.getter.call()) + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_y.getter()) + assertEquals(2, c_y.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_y.getter()) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt b/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt new file mode 100644 index 00000000000..85043fc9d64 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt @@ -0,0 +1,12 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* + +fun String.foo(x: String) = this + x +fun String?.bar(x: String) = x + +fun box() = + (""::foo).call("O") + (null::bar).call("K") \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt new file mode 100644 index 00000000000..233f9b5b37f --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt @@ -0,0 +1,45 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +class C(val x: Int, var y: Int) + +val C.xx: Int + get() = x + +var C.yy: Int + get() = y + set(value) { y = value } + + +val c = C(1, 2) + +val c_xx = c::xx +val c_y = c::y +val c_yy = c::yy + +fun box(): String { + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt b/compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt new file mode 100644 index 00000000000..69f0e53c2a5 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt @@ -0,0 +1,16 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +class Outer(val x: String) { + inner class Inner(val y: String) { + fun foo() = x + y + } +} + +fun box(): String { + val innerCtor = Outer("O")::Inner + val inner = innerCtor.call("K") + return inner.foo() +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt b/compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt new file mode 100644 index 00000000000..19212abf35a --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt @@ -0,0 +1,40 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +// FILE: J.java +public class J { + public final int finalField; + public String mutableField; + + public J(int f, String m) { + this.finalField = f; + this.mutableField = m; + } +} + +// FILE: K.kt +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun box(): String { + val j = J(0, "") + + val jf = j::finalField + val jm = j::mutableField + + assertEquals(0, jf.getter()) + assertEquals(0, jf.getter.call()) + assertEquals("", jm.getter()) + assertEquals("", jm.getter.call()) + + jm.setter("1") + assertEquals("1", j.mutableField) + + jm.setter.call("2") + assertEquals("2", j.mutableField) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt b/compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt new file mode 100644 index 00000000000..0742577fcc4 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt @@ -0,0 +1,35 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +// FILE: J.java +public class J { + private final int param; + + public J(int param) { + this.param = param; + } + + public String foo(int[] arr, Object[] arr2, Integer y) { + return "" + param + arr[0] + arr2[0] + y; + } +} + +// FILE: K.kt +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun box(): String { + val f = J(0)::foo + assertEquals( + listOf(IntArray::class.java, Array::class.java, Integer::class.java), + f.parameters.map { it.type.javaType } + ) + assertEquals(String::class.java, f.returnType.javaType) + + assertEquals("01A2", f.call(intArrayOf(1), arrayOf("A"), 2)) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt new file mode 100644 index 00000000000..dd7311f95f4 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt @@ -0,0 +1,53 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +class Host { + companion object { + @JvmStatic val x = 1 + @JvmStatic var y = 2 + + @JvmStatic val xx: Int + get() = x + + @JvmStatic var yy: Int + get() = y + set(value) { y = value } + } +} + +val c_x = Host.Companion::x +val c_xx = Host.Companion::xx +val c_y = Host.Companion::y +val c_yy = Host.Companion::yy + +fun box(): String { + assertEquals(1, c_x.getter()) + assertEquals(1, c_x.getter.call()) + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_y.getter()) + assertEquals(2, c_y.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_y.getter()) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt new file mode 100644 index 00000000000..1169f50791e --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt @@ -0,0 +1,19 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* + +object Host { + @JvmStatic fun foo(x: String) = x +} + +class CompanionOwner { + companion object { + @JvmStatic fun bar(x: String) = x + } +} + +fun box(): String = + (Host::foo).call("O") + (CompanionOwner.Companion::bar).call("K") \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt new file mode 100644 index 00000000000..3c6e3854f1c --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt @@ -0,0 +1,51 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +object Host { + @JvmStatic val x = 1 + @JvmStatic var y = 2 + + @JvmStatic val xx: Int + get() = x + + @JvmStatic var yy: Int + get() = y + set(value) { y = value } +} + +val c_x = Host::x +val c_xx = Host::xx +val c_y = Host::y +val c_yy = Host::yy + +fun box(): String { + assertEquals(1, c_x.getter()) + assertEquals(1, c_x.getter.call()) + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_y.getter()) + assertEquals(2, c_y.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_y.getter()) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt b/compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt new file mode 100644 index 00000000000..34f6aa7ecb1 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt @@ -0,0 +1,14 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* + +class C(val k: String) { + fun foo(s: String) = s + k +} + +fun box(): String = + C("K")::foo.call("O") + diff --git a/compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt new file mode 100644 index 00000000000..0502c2a573d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt @@ -0,0 +1,50 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +class C(val x: Int, var y: Int) { + val xx: Int + get() = x + + var yy: Int + get() = y + set(value) { y = value } +} + +val c = C(1, 2) + +val c_x = c::x +val c_xx = c::xx +val c_y = c::y +val c_yy = c::yy + +fun box(): String { + assertEquals(1, c_x.getter()) + assertEquals(1, c_x.getter.call()) + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_y.getter()) + assertEquals(2, c_y.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_y.getter()) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt b/compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt new file mode 100644 index 00000000000..81195ecda26 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt @@ -0,0 +1,19 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* + +object Host { + fun foo(x: String) = x +} + +class CompanionOwner { + companion object { + fun bar(x: String) = x + } +} + +fun box(): String = + (Host::foo).call("O") + (CompanionOwner.Companion::bar).call("K") \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt b/compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt new file mode 100644 index 00000000000..2fb29097eb6 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt @@ -0,0 +1,51 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +object Host { + val x = 1 + var y = 2 + + val xx: Int + get() = x + + var yy: Int + get() = y + set(value) { y = value } +} + +val c_x = Host::x +val c_xx = Host::xx +val c_y = Host::y +val c_yy = Host::yy + +fun box(): String { + assertEquals(1, c_x.getter()) + assertEquals(1, c_x.getter.call()) + assertEquals(1, c_xx.getter()) + assertEquals(1, c_xx.getter.call()) + assertEquals(2, c_y.getter()) + assertEquals(2, c_y.getter.call()) + assertEquals(2, c_yy.getter()) + assertEquals(2, c_yy.getter.call()) + + c_y.setter(10) + assertEquals(10, c_y.getter()) + assertEquals(10, c_yy.getter()) + + c_yy.setter(20) + assertEquals(20, c_y.getter()) + assertEquals(20, c_yy.getter()) + + c_y.setter.call(100) + assertEquals(100, c_yy.getter.call()) + + c_yy.setter.call(200) + assertEquals(200, c_y.getter.call()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt b/compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt new file mode 100644 index 00000000000..0632f21ab4e --- /dev/null +++ b/compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt @@ -0,0 +1,13 @@ +// TODO: muted automatically, investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.test.assertEquals + +fun String.extFun(k: String, s: String = "") = this + k + s + +fun box(): String { + val sExtFun = "O"::extFun + return sExtFun.callBy(mapOf(sExtFun.parameters[0] to "K")) +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt b/compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt new file mode 100644 index 00000000000..a6933bfecca --- /dev/null +++ b/compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt @@ -0,0 +1,12 @@ +// TODO: muted automatically, investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.test.assertEquals + +val String.plusK: String + get() = this + "K" + +fun box(): String = + ("O"::plusK).getter.callBy(mapOf()) \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt b/compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt new file mode 100644 index 00000000000..406b38ba1b2 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt @@ -0,0 +1,19 @@ +// TODO: muted automatically, investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +object Host { + @JvmStatic fun concat(s1: String, s2: String, s3: String = "K", s4: String = "x") = + s1 + s2 + s3 + s4 +} + +fun box(): String { + val concat = Host::concat + val concatParams = concat.parameters + return concat.callBy(mapOf( + concatParams[0] to "", + concatParams[1] to "O", + concatParams[3] to "" + )) +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/modifiers/parameters.kt b/compiler/testData/codegen/box/reflection/modifiers/parameters.kt index e78c93aeb4c..966d96ebddc 100644 --- a/compiler/testData/codegen/box/reflection/modifiers/parameters.kt +++ b/compiler/testData/codegen/box/reflection/modifiers/parameters.kt @@ -5,6 +5,7 @@ import kotlin.test.assertTrue import kotlin.test.assertFalse +import kotlin.test.assertEquals inline fun Unit.foo( noinline coroutine x: Unit.() -> Continuation, @@ -14,14 +15,13 @@ inline fun Unit.foo( fun box(): String { val p = Unit::foo.parameters + assertEquals(2, p.size) + assertFalse(p[0].isVararg) - assertFalse(p[0].isCoroutine) + assertTrue(p[0].isCoroutine) - assertFalse(p[1].isVararg) - assertTrue(p[1].isCoroutine) - - assertTrue(p[2].isVararg) - assertFalse(p[2].isCoroutine) + assertTrue(p[1].isVararg) + assertFalse(p[1].isCoroutine) return "OK" } diff --git a/compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt b/compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt new file mode 100644 index 00000000000..69aea956d07 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt @@ -0,0 +1,27 @@ +// TODO: muted automatically, investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT +import kotlin.reflect.KParameter +import kotlin.test.assertEquals + +class Outer(val s1: String) { + inner class Inner(val s2: String, val s3: String = "K") { + val result = s1 + s2 + s3 + } +} + +fun KParameter.check(name: String) { + assertEquals(name, this.name!!) + assertEquals(KParameter.Kind.VALUE, this.kind) +} + +fun box(): String { + val ctor = Outer("O")::Inner + val ctorPararms = ctor.parameters + + ctorPararms[0].check("s2") + ctorPararms[1].check("s3") + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt b/compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt new file mode 100644 index 00000000000..646eed1de73 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt @@ -0,0 +1,26 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +object Host { + fun foo(i: Int, s: String) {} +} + +fun box(): String { + val fooParams = Host::foo.parameters + + assertEquals(2, fooParams.size) + + assertEquals("i", fooParams[0].name) + assertEquals(Int::class.java, fooParams[0].type.javaType) + + assertEquals("s", fooParams[1].name) + assertEquals(String::class.java, fooParams[1].type.javaType) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/parameters/boundReferences.kt b/compiler/testData/codegen/box/reflection/parameters/boundReferences.kt new file mode 100644 index 00000000000..0b47967fd42 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/parameters/boundReferences.kt @@ -0,0 +1,35 @@ +// TODO: investigate should it be ran for JS or not +// IGNORE_BACKEND: JS + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.* + +class C { + fun foo() {} + var bar = "OK" +} + +fun C.extFun(i: Int) {} + +fun KParameter.check(name: String) { + assertEquals(name, this.name!!) + assertEquals(KParameter.Kind.VALUE, this.kind) +} + +fun box(): String { + val cFoo = C()::foo + val cBar = C()::bar + val cExtFun = C()::extFun + + assertEquals(0, cFoo.parameters.size) + assertEquals(0, cBar.getter.parameters.size) + assertEquals(1, cBar.setter.parameters.size) + + assertEquals(1, cExtFun.parameters.size) + cExtFun.parameters[0].check("i") + + return "OK" +} 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 ada156ea026..dab0804b81e 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 @@ -12348,6 +12348,93 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/reflection/call/bound") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Bound extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInBound() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("companionObjectPropertyAccessors.kt") + public void testCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("extensionFunction.kt") + public void testExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("extensionPropertyAccessors.kt") + public void testExtensionPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("innerClassConstructor.kt") + public void testInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("javaInstanceField.kt") + public void testJavaInstanceField() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt"); + doTest(fileName); + } + + @TestMetadata("javaInstanceMethod.kt") + public void testJavaInstanceMethod() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticCompanionObjectPropertyAccessors.kt") + public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticObjectFunction.kt") + public void testJvmStaticObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticObjectPropertyAccessors.kt") + public void testJvmStaticObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("memberPropertyAccessors.kt") + public void testMemberPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("objectFunction.kt") + public void testObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt"); + doTest(fileName); + } + + @TestMetadata("objectPropertyAccessors.kt") + public void testObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/callBy") @@ -12358,6 +12445,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("boundExtensionFunction.kt") + public void testBoundExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("boundExtensionPropertyAcessor.kt") + public void testBoundExtensionPropertyAcessor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt"); + doTest(fileName); + } + + @TestMetadata("boundJvmStaticInObject.kt") + public void testBoundJvmStaticInObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt"); + doTest(fileName); + } + @TestMetadata("companionObject.kt") public void testCompanionObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); @@ -13546,6 +13651,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("boundInnerClassConstructor.kt") + public void testBoundInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("boundObjectMemberReferences.kt") + public void testBoundObjectMemberReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt"); + doTest(fileName); + } + + @TestMetadata("boundReferences.kt") + public void testBoundReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.kt"); + doTest(fileName); + } + @TestMetadata("findParameterByName.kt") public void testFindParameterByName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java index 01c41234eea..56242791130 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java @@ -332,12 +332,6 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } - @TestMetadata("throwInTryWithHandleResult.kt") - public void testThrowInTryWithHandleResult() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); - doTest(fileName); - } - } @TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ff44ead343f..3d6a1cb21e9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12348,6 +12348,93 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/reflection/call/bound") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Bound extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInBound() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("companionObjectPropertyAccessors.kt") + public void testCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("extensionFunction.kt") + public void testExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("extensionPropertyAccessors.kt") + public void testExtensionPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("innerClassConstructor.kt") + public void testInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("javaInstanceField.kt") + public void testJavaInstanceField() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt"); + doTest(fileName); + } + + @TestMetadata("javaInstanceMethod.kt") + public void testJavaInstanceMethod() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticCompanionObjectPropertyAccessors.kt") + public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticObjectFunction.kt") + public void testJvmStaticObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt"); + doTest(fileName); + } + + @TestMetadata("jvmStaticObjectPropertyAccessors.kt") + public void testJvmStaticObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("memberPropertyAccessors.kt") + public void testMemberPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("objectFunction.kt") + public void testObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt"); + doTest(fileName); + } + + @TestMetadata("objectPropertyAccessors.kt") + public void testObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/callBy") @@ -12358,6 +12445,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("boundExtensionFunction.kt") + public void testBoundExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("boundExtensionPropertyAcessor.kt") + public void testBoundExtensionPropertyAcessor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt"); + doTest(fileName); + } + + @TestMetadata("boundJvmStaticInObject.kt") + public void testBoundJvmStaticInObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt"); + doTest(fileName); + } + @TestMetadata("companionObject.kt") public void testCompanionObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); @@ -13546,6 +13651,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("boundInnerClassConstructor.kt") + public void testBoundInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("boundObjectMemberReferences.kt") + public void testBoundObjectMemberReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt"); + doTest(fileName); + } + + @TestMetadata("boundReferences.kt") + public void testBoundReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.kt"); + doTest(fileName); + } + @TestMetadata("findParameterByName.kt") public void testFindParameterByName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt index 924d5d6b4f7..e1717f49165 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -67,16 +67,30 @@ internal abstract class FunctionCaller( } } + // TODO fix 'callBy' for bound (and non-bound) inner class constructor references + // See https://youtrack.jetbrains.com/issue/KT-14990 + class BoundConstructor(constructor: ReflectConstructor<*>, private val boundReceiver: Any?) : + FunctionCaller>( + constructor, constructor.declaringClass, null, + constructor.genericParameterTypes + ) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.newInstance(*argsWithReceiver(boundReceiver, args)) + } + } + // Methods abstract class Method( method: ReflectMethod, - requiresInstance: Boolean = !Modifier.isStatic(method.modifiers) + requiresInstance: Boolean = !Modifier.isStatic(method.modifiers), + parameterTypes: Array = method.genericParameterTypes ) : FunctionCaller( method, method.genericReturnType, if (requiresInstance) method.declaringClass else null, - method.genericParameterTypes + parameterTypes ) { private val isVoidMethod = returnType == Void.TYPE @@ -98,7 +112,7 @@ internal abstract class FunctionCaller( class InstanceMethod(method: ReflectMethod) : Method(method) { override fun call(args: Array<*>): Any? { checkArguments(args) - return callMethod(args[0], args.copyOfRange(1, args.size)) + return callMethod(args[0], args.dropFirstArg()) } } @@ -106,7 +120,31 @@ internal abstract class FunctionCaller( override fun call(args: Array<*>): Any? { checkArguments(args) checkObjectInstance(args.firstOrNull()) - return callMethod(null, args.copyOfRange(1, args.size)) + return callMethod(null, args.dropFirstArg()) + } + } + + class BoundStaticMethod(method: ReflectMethod, private val boundReceiver: Any?) : + Method(method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return callMethod(null, argsWithReceiver(boundReceiver, args)) + } + } + + class BoundInstanceMethod(method: ReflectMethod, private val boundReceiver: Any?) : + Method(method, requiresInstance = false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return callMethod(boundReceiver, args) + } + } + + class BoundJvmStaticInObject(method: ReflectMethod) : + Method(method, requiresInstance = false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return callMethod(null, args) } } @@ -161,21 +199,32 @@ internal abstract class FunctionCaller( } } - class ClassCompanionFieldGetter( - field: ReflectField, - klass: Class<*> - ) : FunctionCaller( - field, - field.genericType, - klass, - emptyArray() - ) { + class ClassCompanionFieldGetter(field: ReflectField, klass: Class<*>) : + FunctionCaller(field, field.genericType, klass, emptyArray()) { override fun call(args: Array<*>): Any? { checkArguments(args) return member.get(args.first()) } } + class BoundInstanceFieldGetter(field: ReflectField, private val boundReceiver: Any?) : + FieldGetter(field, requiresInstance = false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.get(boundReceiver) + } + } + + class BoundJvmStaticInObjectFieldGetter(field: ReflectField) : FieldGetter(field, requiresInstance = false) + + class BoundClassCompanionFieldGetter(field: ReflectField, private val boundReceiver: Any?) : + FieldGetter(field, requiresInstance = false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.get(boundReceiver) + } + } + class StaticFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) class InstanceFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) @@ -187,18 +236,53 @@ internal abstract class FunctionCaller( } } - class ClassCompanionFieldSetter( - field: ReflectField, - klass: Class<*> - ) : FunctionCaller( - field, - Void.TYPE, - klass, - arrayOf(field.genericType) - ) { + class ClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) : + FunctionCaller(field, Void.TYPE, klass, arrayOf(field.genericType)) { override fun call(args: Array<*>): Any? { checkArguments(args) - return member.set(instanceClass, args.last()) + return member.set(null, args.last()) } } + + class BoundInstanceFieldSetter(field: ReflectField, notNull: Boolean, private val boundReceiver: Any?) : + FieldSetter(field, notNull, false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.set(boundReceiver, args.first()) + } + } + + class BoundJvmStaticInObjectFieldSetter(field: ReflectField, notNull: Boolean) : + FieldSetter(field, notNull, requiresInstance = false) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.set(null, args.last()) + } + } + + class BoundClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) : + FunctionCaller(field, Void.TYPE, klass, arrayOf(field.genericType)) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.set(null, args.last()) + } + } + + + companion object { + // TODO lazily allocate array at bound callers? + fun argsWithReceiver(receiver: Any?, args: Array): Array = + arrayOfNulls(args.size + 1).apply { + this[0] = receiver + System.arraycopy(args, 0, this, 1, args.size) + } + + @Suppress("UNCHECKED_CAST") + inline fun Array.dropFirst(): Array = + if (size <= 1) emptyArray() else copyOfRange(1, size) as Array + + @Suppress("UNCHECKED_CAST") + fun Array<*>.dropFirstArg(): Array = + (this as Array).dropFirst() + } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index 9ec892f6286..cd3092f5829 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -35,6 +35,8 @@ internal abstract class KCallableImpl : KCallable { abstract val container: KDeclarationContainerImpl + abstract val isBound: Boolean + private val annotations_ = ReflectProperties.lazySoft { descriptor.computeAnnotations() } override val annotations: List get() = annotations_() @@ -44,11 +46,11 @@ internal abstract class KCallableImpl : KCallable { val result = ArrayList() var index = 0 - if (descriptor.dispatchReceiverParameter != null) { + if (descriptor.dispatchReceiverParameter != null && !isBound) { result.add(KParameterImpl(this, index++, KParameter.Kind.INSTANCE) { descriptor.dispatchReceiverParameter!! }) } - if (descriptor.extensionReceiverParameter != null) { + if (descriptor.extensionReceiverParameter != null && !isBound) { result.add(KParameterImpl(this, index++, KParameter.Kind.EXTENSION_RECEIVER) { descriptor.extensionReceiverParameter!! }) } 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 1cebfacf242..abed0a8e94c 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -50,6 +50,8 @@ internal class KFunctionImpl private constructor( descriptor ) + override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER + override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { container.findFunctionDescriptor(name, signature) } @@ -77,13 +79,15 @@ internal class KFunctionImpl private constructor( } when (member) { - is Constructor<*> -> FunctionCaller.Constructor(member) + is Constructor<*> -> + createConstructorCaller(member) is Method -> when { - !Modifier.isStatic(member.modifiers) -> FunctionCaller.InstanceMethod(member) + !Modifier.isStatic(member.modifiers) -> + createInstanceMethodCaller(member) descriptor.annotations.findAnnotation(JVM_STATIC) != null -> - FunctionCaller.JvmStaticInObject(member) - - else -> FunctionCaller.StaticMethod(member) + createJvmStaticInObjectCaller(member) + else -> + createStaticMethodCaller(member) } else -> throw KotlinReflectionInternalError("Call is not yet supported for this function: $descriptor (member = $member)") } @@ -112,21 +116,35 @@ internal class KFunctionImpl private constructor( } when (member) { - is Constructor<*> -> FunctionCaller.Constructor(member) + is Constructor<*> -> + createConstructorCaller(member) is Method -> when { // Note that static $default methods for @JvmStatic functions are generated differently in objects and companion objects. // In objects, $default's signature does _not_ contain the additional object instance parameter, // as opposed to companion objects where the first parameter is the companion object instance. descriptor.annotations.findAnnotation(JVM_STATIC) != null && !(descriptor.containingDeclaration as ClassDescriptor).isCompanionObject -> - FunctionCaller.JvmStaticInObject(member) + createJvmStaticInObjectCaller(member) - else -> FunctionCaller.StaticMethod(member) + else -> + createStaticMethodCaller(member) } else -> null } } + private fun createStaticMethodCaller(member: Method) = + if (isBound) FunctionCaller.BoundStaticMethod(member, boundReceiver) else FunctionCaller.StaticMethod(member) + + private fun createJvmStaticInObjectCaller(member: Method) = + if (isBound) FunctionCaller.BoundJvmStaticInObject(member) else FunctionCaller.JvmStaticInObject(member) + + private fun createInstanceMethodCaller(member: Method) = + if (isBound) FunctionCaller.BoundInstanceMethod(member, boundReceiver) else FunctionCaller.InstanceMethod(member) + + private fun createConstructorCaller(member: Constructor<*>) = + if (isBound) FunctionCaller.BoundConstructor(member, boundReceiver) else FunctionCaller.Constructor(member) + override fun getArity() = caller.arity override val isInline: Boolean 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 dbed24829e2..f47847a0042 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -17,11 +17,12 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import kotlin.jvm.internal.CallableReference 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, null) + constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, CallableReference.NO_RECEIVER) 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 57d47e6760d..3a99b8c53b2 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -37,7 +37,7 @@ internal abstract class KPropertyImpl private constructor( override val name: String, val signature: String, descriptorInitialValue: PropertyDescriptor?, - private val boundReceiver: Any? = CallableReference.NO_RECEIVER + val boundReceiver: Any? ) : KCallableImpl(), KProperty { constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this( container, name, signature, null, boundReceiver @@ -47,9 +47,12 @@ internal abstract class KPropertyImpl private constructor( container, descriptor.name.asString(), RuntimeTypeMapper.mapPropertySignature(descriptor).asString(), - descriptor + descriptor, + CallableReference.NO_RECEIVER ) + override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER + private val javaField_ = ReflectProperties.lazySoft { val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor) when (jvmSignature) { @@ -116,6 +119,8 @@ internal abstract class KPropertyImpl private constructor( override val defaultCaller: FunctionCaller<*>? get() = null + override val isBound: Boolean get() = property.isBound + override val isInline: Boolean get() = descriptor.isInline override val isExternal: Boolean get() = descriptor.isExternal override val isOperator: Boolean get() = descriptor.isOperator @@ -169,15 +174,27 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool fun computeFieldCaller(field: Field): FunctionCaller = when { isInsideClassCompanionObject() -> { val klass = (descriptor.containingDeclaration as ClassDescriptor).toJavaClass()!! - if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass) - else FunctionCaller.ClassCompanionFieldSetter(field, klass) + if (isGetter) + if (isBound) FunctionCaller.BoundClassCompanionFieldGetter(field, klass) + else FunctionCaller.ClassCompanionFieldGetter(field, klass) + else + if (isBound) FunctionCaller.BoundClassCompanionFieldSetter(field, klass) + else FunctionCaller.ClassCompanionFieldSetter(field, klass) } !Modifier.isStatic(field.modifiers) -> - if (isGetter) FunctionCaller.InstanceFieldGetter(field) - else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty()) + if (isGetter) + if (isBound) FunctionCaller.BoundInstanceFieldGetter(field, property.boundReceiver) + else FunctionCaller.InstanceFieldGetter(field) + else + if (isBound) FunctionCaller.BoundInstanceFieldSetter(field, isNotNullProperty(), property.boundReceiver) + else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty()) isJvmStaticProperty() -> - if (isGetter) FunctionCaller.JvmStaticInObjectFieldGetter(field) - else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty()) + if (isGetter) + if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldGetter(field) + else FunctionCaller.JvmStaticInObjectFieldGetter(field) + else + if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldSetter(field, isNotNullProperty()) + else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty()) else -> if (isGetter) FunctionCaller.StaticFieldGetter(field) else FunctionCaller.StaticFieldSetter(field, isNotNullProperty()) @@ -203,9 +220,15 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool when { accessor == null -> computeFieldCaller(property.javaField!!) - !Modifier.isStatic(accessor.modifiers) -> FunctionCaller.InstanceMethod(accessor) - isJvmStaticProperty() -> FunctionCaller.JvmStaticInObject(accessor) - else -> FunctionCaller.StaticMethod(accessor) + !Modifier.isStatic(accessor.modifiers) -> + if (isBound) FunctionCaller.BoundInstanceMethod(accessor, property.boundReceiver) + else FunctionCaller.InstanceMethod(accessor) + isJvmStaticProperty() -> + if (isBound) FunctionCaller.BoundJvmStaticInObject(accessor) + else FunctionCaller.JvmStaticInObject(accessor) + else -> + if (isBound) FunctionCaller.BoundStaticMethod(accessor, property.boundReceiver) + else FunctionCaller.StaticMethod(accessor) } } is JavaField -> { @@ -217,7 +240,8 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool else jvmSignature.setterMethod ?: throw KotlinReflectionInternalError( "No source found for setter of Java method property: ${jvmSignature.getterMethod}" ) - FunctionCaller.InstanceMethod(method) + if (isBound) FunctionCaller.BoundInstanceMethod(method, property.boundReceiver) + else FunctionCaller.InstanceMethod(method) } } } 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 ed73255d41e..bc42c0ef6dd 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 @@ -1877,7 +1877,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("companionObjectReceiver.kt") public void testCompanionObjectReceiver() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); - doTest(fileName); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } @TestMetadata("enumEntryMember.kt") @@ -1931,12 +1937,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @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); } @@ -1946,6 +1946,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } + @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"); @@ -14857,6 +14863,171 @@ 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/reflection/call/bound") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Bound extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInBound() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("companionObjectPropertyAccessors.kt") + public void testCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.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("extensionFunction.kt") + public void testExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.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("extensionPropertyAccessors.kt") + public void testExtensionPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.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("innerClassConstructor.kt") + public void testInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.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("javaInstanceField.kt") + public void testJavaInstanceField() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.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("javaInstanceMethod.kt") + public void testJavaInstanceMethod() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.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("jvmStaticCompanionObjectPropertyAccessors.kt") + public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.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("jvmStaticObjectFunction.kt") + public void testJvmStaticObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.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("jvmStaticObjectPropertyAccessors.kt") + public void testJvmStaticObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.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("memberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.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("memberPropertyAccessors.kt") + public void testMemberPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.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("objectFunction.kt") + public void testObjectFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.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("objectPropertyAccessors.kt") + public void testObjectPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.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/reflection/callBy") @@ -14867,6 +15038,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("boundExtensionFunction.kt") + public void testBoundExtensionFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.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("boundExtensionPropertyAcessor.kt") + public void testBoundExtensionPropertyAcessor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.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("boundJvmStaticInObject.kt") + public void testBoundJvmStaticInObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.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("companionObject.kt") public void testCompanionObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); @@ -17009,6 +17216,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("boundInnerClassConstructor.kt") + public void testBoundInnerClassConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.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("boundObjectMemberReferences.kt") + public void testBoundObjectMemberReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.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("boundReferences.kt") + public void testBoundReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.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("findParameterByName.kt") public void testFindParameterByName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt");