Support inline classes in function signatures in call/callBy
#KT-25664 Fixed #KT-26748 Open #KT-26765 Open
This commit is contained in:
+37
@@ -0,0 +1,37 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
class C {
|
||||
private var member: S = S("")
|
||||
|
||||
fun unboundRef() = C::member.apply { isAccessible = true }
|
||||
fun boundRef() = this::member.apply { isAccessible = true }
|
||||
}
|
||||
|
||||
private var topLevel: S = S("")
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
assertEquals(Unit, c.unboundRef().setter.call(c, S("ab")))
|
||||
assertEquals(S("ab"), c.unboundRef().call(c))
|
||||
assertEquals(S("ab"), c.unboundRef().getter.call(c))
|
||||
|
||||
assertEquals(Unit, c.boundRef().setter.call(S("cd")))
|
||||
assertEquals(S("cd"), c.boundRef().call())
|
||||
assertEquals(S("cd"), c.boundRef().getter.call())
|
||||
|
||||
val topLevel = ::topLevel.apply { isAccessible = true }
|
||||
assertEquals(Unit, topLevel.setter.call(S("ef")))
|
||||
assertEquals(S("ef"), topLevel.call())
|
||||
assertEquals(S("ef"), topLevel.getter.call())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
class C {
|
||||
fun member(x: S, y: String): S = x + S(y)
|
||||
}
|
||||
|
||||
fun topLevel(x: String, y: S): S = S(x) + y
|
||||
|
||||
/* TODO: support constructors with inline class types in the signature (KT-26765)
|
||||
class D {
|
||||
inner class Inner(x: S, y: S) {
|
||||
val result = x + y
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fun S.extension(y: S): S = this + y
|
||||
|
||||
fun S.extension2(): String = value
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(S("ab"), C::member.call(C(), S("a"), "b"))
|
||||
assertEquals(S("cd"), ::topLevel.call("c", S("d")))
|
||||
// assertEquals(S("ef"), D::Inner.call(D(), S("e"), S("f")).result)
|
||||
assertEquals(S("gh"), S::extension.call(S("g"), S("h")))
|
||||
assertEquals("_", S::extension2.call(S("_")))
|
||||
|
||||
assertEquals(S("ij"), C()::member.call(S("i"), "j"))
|
||||
// assertEquals(S("kl"), D()::Inner.call(S("k"), S("l")).result)
|
||||
assertEquals(S("mn"), S("m")::extension.call(S("n")))
|
||||
assertEquals("_", S("_")::extension2.call())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
object C {
|
||||
@JvmStatic
|
||||
private var p: S = S("")
|
||||
|
||||
fun boundRef() = this::p.apply { isAccessible = true }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val unboundRef = C::class.members.single { it.name == "p" } as KMutableProperty1<C, S>
|
||||
unboundRef.isAccessible = true
|
||||
assertEquals(Unit, unboundRef.setter.call(C, S("ab")))
|
||||
assertEquals(S("ab"), unboundRef.call(C))
|
||||
assertEquals(S("ab"), unboundRef.getter.call(C))
|
||||
|
||||
val boundRef = C.boundRef()
|
||||
assertEquals(Unit, boundRef.setter.call(S("cd")))
|
||||
assertEquals(S("cd"), boundRef.call())
|
||||
assertEquals(S("cd"), boundRef.getter.call())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
object C {
|
||||
@JvmStatic
|
||||
fun foo(x: S, y: String): S = x + S(y)
|
||||
}
|
||||
|
||||
interface I {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun bar(x: String, y: S): S = S(x) + y
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(S("ab"), C::foo.call(S("a"), "b"))
|
||||
assertEquals(S("cd"), (I)::bar.call("c", S("d")))
|
||||
|
||||
val unboundFoo = C::class.members.single { it.name == "foo" } as KFunction<*>
|
||||
assertEquals(S("ef"), unboundFoo.call(C, S("e"), "f"))
|
||||
|
||||
val unboundBar = I.Companion::class.members.single { it.name == "bar" } as KFunction<*>
|
||||
assertEquals(S("gh"), unboundBar.call(I, "g", S("h")))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
class C {
|
||||
var member: S = S("")
|
||||
|
||||
private var suffix = S("")
|
||||
var S.memExt: S
|
||||
get() = this + suffix
|
||||
set(value) { suffix = this + value }
|
||||
}
|
||||
|
||||
var topLevel: S = S("")
|
||||
|
||||
private var suffix = S("")
|
||||
var S.ext: S
|
||||
get() = this + suffix
|
||||
set(value) { suffix = this + value }
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
assertEquals(Unit, C::member.setter.call(c, S("ab")))
|
||||
assertEquals(S("ab"), C::member.call(c))
|
||||
assertEquals(S("ab"), C::member.getter.call(c))
|
||||
|
||||
assertEquals(Unit, c::member.setter.call(S("cd")))
|
||||
assertEquals(S("cd"), c::member.call())
|
||||
assertEquals(S("cd"), c::member.getter.call())
|
||||
|
||||
val memExt = C::class.members.single { it.name == "memExt" } as KMutableProperty2<C, S, S>
|
||||
assertEquals(Unit, memExt.setter.call(c, S(""), S("f")))
|
||||
assertEquals(S("ef"), memExt.call(c, S("e")))
|
||||
assertEquals(S("ef"), memExt.getter.call(c, S("e")))
|
||||
|
||||
assertEquals(Unit, ::topLevel.setter.call(S("gh")))
|
||||
assertEquals(S("gh"), ::topLevel.call())
|
||||
assertEquals(S("gh"), ::topLevel.getter.call())
|
||||
|
||||
assertEquals(Unit, S::ext.setter.call(S(""), S("j")))
|
||||
assertEquals(S("ij"), S::ext.call(S("i")))
|
||||
assertEquals(S("ij"), S::ext.getter.call(S("i")))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String) {
|
||||
operator fun plus(other: S): S = S(this.value + other.value)
|
||||
}
|
||||
|
||||
class C {
|
||||
fun member(a: S, b: S = S("b")): S = a + b
|
||||
}
|
||||
|
||||
fun topLevel(c: S, d: S = S("d")): S = c + d
|
||||
|
||||
/* TODO: support constructors with inline class types in the signature (KT-26765)
|
||||
class D(e: S, f: S = S("f")) {
|
||||
val result = e + f
|
||||
}
|
||||
*/
|
||||
|
||||
fun S.extension(h: S = S("h")): S = this + h
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(S("ab"), C::member.callBy(C::member.parameters.filter { it.name != "b" }.associate {
|
||||
it to (if (it.name == "a") S("a") else C())
|
||||
}))
|
||||
|
||||
assertEquals(S("cd"), ::topLevel.callBy(::topLevel.parameters.filter { it.name != "d" }.associate { it to S("c") }))
|
||||
|
||||
// assertEquals(S("ef"), ::D.callBy(::D.parameters.filter { it.name != "f" }.associate { it to S("e") }).result)
|
||||
|
||||
assertEquals(S("gh"), S::extension.callBy(S::extension.parameters.filter { it.name != "h" }.associate { it to S("g") }))
|
||||
|
||||
|
||||
val boundMember = C()::member
|
||||
assertEquals(S("ab"), boundMember.callBy(boundMember.parameters.associate { it to S(it.name!!) }))
|
||||
|
||||
val boundExtension = S("g")::extension
|
||||
assertEquals(S("gh"), boundExtension.callBy(boundExtension.parameters.associate { it to S(it.name!!) }))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.jvm.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class S(val value: String)
|
||||
|
||||
fun S.foo(x: Int, s: S): S = this
|
||||
|
||||
/* TODO: Support calling members of inline classes in reflection (KT-26748)
|
||||
inline class T(val s: S) {
|
||||
fun bar(u: S): T = this
|
||||
}
|
||||
*/
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(listOf(String::class.java, Int::class.java, String::class.java), S::foo.parameters.map { it.type.javaType })
|
||||
assertEquals(S::class.java, S::foo.returnType.javaType)
|
||||
|
||||
/*
|
||||
assertEquals(listOf(), T::bar.parameters.map { it.type.javaType })
|
||||
assertEquals(String::class.java, T::bar.returnType.javaType)
|
||||
*/
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+48
@@ -17927,6 +17927,44 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/call/inlineClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InlineClasses extends AbstractBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInlineClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldAccessors.kt")
|
||||
public void testFieldAccessors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/fieldAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionsAndConstructors.kt")
|
||||
public void testFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/functionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFieldInObject.kt")
|
||||
public void testJvmStaticFieldInObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFunction.kt")
|
||||
public void testJvmStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
|
||||
@@ -17971,6 +18009,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassFunctionsAndConstructors.kt")
|
||||
public void testInlineClassFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticInCompanionObject.kt")
|
||||
public void testJvmStaticInCompanionObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");
|
||||
@@ -18852,6 +18895,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassInSignature.kt")
|
||||
public void testInlineClassInSignature() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerGenericTypeArgument.kt")
|
||||
public void testInnerGenericTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
|
||||
|
||||
+48
@@ -17927,6 +17927,44 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/call/inlineClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InlineClasses extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInlineClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldAccessors.kt")
|
||||
public void testFieldAccessors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/fieldAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionsAndConstructors.kt")
|
||||
public void testFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/functionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFieldInObject.kt")
|
||||
public void testJvmStaticFieldInObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFunction.kt")
|
||||
public void testJvmStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
|
||||
@@ -17971,6 +18009,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassFunctionsAndConstructors.kt")
|
||||
public void testInlineClassFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticInCompanionObject.kt")
|
||||
public void testJvmStaticInCompanionObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");
|
||||
@@ -18852,6 +18895,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassInSignature.kt")
|
||||
public void testInlineClassInSignature() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerGenericTypeArgument.kt")
|
||||
public void testInnerGenericTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
|
||||
|
||||
+48
@@ -17927,6 +17927,44 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/call/inlineClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InlineClasses extends AbstractIrBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInlineClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldAccessors.kt")
|
||||
public void testFieldAccessors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/fieldAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionsAndConstructors.kt")
|
||||
public void testFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/functionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFieldInObject.kt")
|
||||
public void testJvmStaticFieldInObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFunction.kt")
|
||||
public void testJvmStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
|
||||
@@ -17971,6 +18009,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassFunctionsAndConstructors.kt")
|
||||
public void testInlineClassFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticInCompanionObject.kt")
|
||||
public void testJvmStaticInCompanionObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");
|
||||
@@ -18852,6 +18895,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassInSignature.kt")
|
||||
public void testInlineClassInSignature() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerGenericTypeArgument.kt")
|
||||
public void testInnerGenericTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
|
||||
|
||||
@@ -87,7 +87,7 @@ internal class KFunctionImpl private constructor(
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> throw KotlinReflectionInternalError("Could not compute caller for function: $descriptor (member = $member)")
|
||||
}
|
||||
}.createInlineClassAwareCallerIfNeeded(descriptor)
|
||||
}
|
||||
|
||||
override val defaultCaller: Caller<*>? by ReflectProperties.lazySoft defaultCaller@{
|
||||
@@ -129,7 +129,7 @@ internal class KFunctionImpl private constructor(
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}?.createInlineClassAwareCallerIfNeeded(descriptor, isDefault = true)
|
||||
}
|
||||
|
||||
private fun createStaticMethodCaller(member: Method) =
|
||||
|
||||
@@ -24,6 +24,7 @@ import kotlin.reflect.jvm.internal.JvmPropertySignature.*
|
||||
import kotlin.reflect.jvm.internal.calls.Caller
|
||||
import kotlin.reflect.jvm.internal.calls.CallerImpl
|
||||
import kotlin.reflect.jvm.internal.calls.ThrowingCaller
|
||||
import kotlin.reflect.jvm.internal.calls.createInlineClassAwareCallerIfNeeded
|
||||
|
||||
internal abstract class KPropertyImpl<out R> private constructor(
|
||||
override val container: KDeclarationContainerImpl,
|
||||
@@ -185,7 +186,7 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
fun isNotNullProperty(): Boolean =
|
||||
!TypeUtils.isNullableType(property.descriptor.type)
|
||||
|
||||
fun computeFieldCaller(field: Field): Caller<Field> = when {
|
||||
fun computeFieldCaller(field: Field): CallerImpl<Field> = when {
|
||||
property.descriptor.isJvmFieldPropertyInCompanionObject() || !Modifier.isStatic(field.modifiers) ->
|
||||
if (isGetter)
|
||||
if (isBound) CallerImpl.FieldGetter.BoundInstance(field, property.boundReceiver)
|
||||
@@ -263,7 +264,7 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
return if (isBound) CallerImpl.Method.BoundInstance(accessor, property.boundReceiver)
|
||||
else CallerImpl.Method.Instance(accessor)
|
||||
}
|
||||
}
|
||||
}.createInlineClassAwareCallerIfNeeded(descriptor)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.isJvmFieldPropertyInCompanionObject(): Boolean {
|
||||
|
||||
@@ -26,3 +26,8 @@ internal interface Caller<out M : Member?> {
|
||||
|
||||
internal val Caller<*>.arity: Int
|
||||
get() = parameterTypes.size
|
||||
|
||||
/**
|
||||
* A marker interface that signifies that this caller has a "bound receiver" object which should be used as the dispatch receiver instance.
|
||||
*/
|
||||
interface BoundCaller
|
||||
|
||||
@@ -44,7 +44,7 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
|
||||
// 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?) :
|
||||
class BoundConstructor(constructor: ReflectConstructor<*>, private val boundReceiver: Any?) : BoundCaller,
|
||||
CallerImpl<ReflectConstructor<*>>(
|
||||
constructor, constructor.declaringClass, null,
|
||||
constructor.genericParameterTypes
|
||||
@@ -96,7 +96,7 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundStatic(method: ReflectMethod, private val boundReceiver: Any?) : Method(
|
||||
class BoundStatic(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller, Method(
|
||||
method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()
|
||||
) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
@@ -105,14 +105,15 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstance(method: ReflectMethod, private val boundReceiver: Any?) : Method(method, requiresInstance = false) {
|
||||
class BoundInstance(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller,
|
||||
Method(method, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(boundReceiver, args)
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObject(method: ReflectMethod) : Method(method, requiresInstance = false) {
|
||||
class BoundJvmStaticInObject(method: ReflectMethod) : BoundCaller, Method(method, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(null, args)
|
||||
@@ -145,14 +146,15 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstance(field: ReflectField, private val boundReceiver: Any?) : FieldGetter(field, requiresInstance = false) {
|
||||
class BoundInstance(field: ReflectField, private val boundReceiver: Any?) : BoundCaller,
|
||||
FieldGetter(field, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.get(boundReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObject(field: ReflectField) : FieldGetter(field, requiresInstance = false)
|
||||
class BoundJvmStaticInObject(field: ReflectField) : BoundCaller, FieldGetter(field, requiresInstance = false)
|
||||
}
|
||||
|
||||
sealed class FieldSetter(
|
||||
@@ -188,7 +190,7 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstance(field: ReflectField, notNull: Boolean, private val boundReceiver: Any?) :
|
||||
class BoundInstance(field: ReflectField, notNull: Boolean, private val boundReceiver: Any?) : BoundCaller,
|
||||
FieldSetter(field, notNull, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
@@ -196,7 +198,8 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObject(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull, requiresInstance = false) {
|
||||
class BoundJvmStaticInObject(field: ReflectField, notNull: Boolean) : BoundCaller,
|
||||
FieldSetter(field, notNull, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.set(null, args.last())
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.reflect.jvm.internal.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.reflect.jvm.internal.KotlinReflectionInternalError
|
||||
import kotlin.reflect.jvm.internal.toJavaClass
|
||||
|
||||
/**
|
||||
* A caller that is used whenever the declaration has inline classes in its parameter types or return type.
|
||||
* Each argument of an inline class type is unboxed, and the return value (if it's of an inline class type) is boxed.
|
||||
*/
|
||||
internal class InlineClassAwareCaller<out M : Member>(
|
||||
private val descriptor: CallableMemberDescriptor,
|
||||
private val caller: CallerImpl<M>,
|
||||
private val isDefault: Boolean
|
||||
) : Caller<M> {
|
||||
override val member: M
|
||||
get() = caller.member
|
||||
|
||||
override val returnType: Type
|
||||
get() = caller.returnType
|
||||
|
||||
override val parameterTypes: List<Type>
|
||||
get() = caller.parameterTypes
|
||||
|
||||
private class BoxUnboxData(val argumentRange: IntRange, val unbox: Array<Method?>, val box: Method?) {
|
||||
operator fun component1(): IntRange = argumentRange
|
||||
operator fun component2(): Array<Method?> = unbox
|
||||
operator fun component3(): Method? = box
|
||||
}
|
||||
|
||||
private val data: BoxUnboxData by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
val shift = when {
|
||||
caller is CallerImpl.Method.BoundStatic -> {
|
||||
// Bound reference to a static method is only possible for a top level extension function/property,
|
||||
// and in that case the number of expected arguments is one less than usual, hence -1
|
||||
-1
|
||||
}
|
||||
descriptor.dispatchReceiverParameter != null && caller !is BoundCaller -> 1
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val extraArgumentsTail = if (isDefault) 2 else 0
|
||||
|
||||
val kotlinParameterTypes =
|
||||
listOfNotNull(descriptor.extensionReceiverParameter?.type) +
|
||||
descriptor.valueParameters.map(ValueParameterDescriptor::getType)
|
||||
val expectedArgsSize = kotlinParameterTypes.size + shift + extraArgumentsTail
|
||||
if (arity != expectedArgsSize) {
|
||||
throw KotlinReflectionInternalError(
|
||||
"Inconsistent number of parameters in the descriptor and Java reflection object: $arity != $expectedArgsSize\n" +
|
||||
"Calling: $descriptor\n" +
|
||||
"Parameter types: ${this.parameterTypes})\n" +
|
||||
"Default: $isDefault"
|
||||
)
|
||||
}
|
||||
|
||||
// maxOf is needed because in case of a bound top level extension, shift can be -1 (see above). But in that case, we need not unbox
|
||||
// the extension receiver argument, since it has already been unboxed at compile time and generated into the reference
|
||||
val argumentRange = maxOf(shift, 0) until (kotlinParameterTypes.size + shift)
|
||||
|
||||
val unbox = Array(expectedArgsSize) { i ->
|
||||
if (i in argumentRange) {
|
||||
kotlinParameterTypes[i - shift].toInlineClass()?.getUnboxMethod()
|
||||
} else null
|
||||
}
|
||||
|
||||
val box = descriptor.returnType!!.toInlineClass()?.getBoxMethod()
|
||||
|
||||
BoxUnboxData(argumentRange, unbox, box)
|
||||
}
|
||||
|
||||
override fun call(args: Array<*>): Any? {
|
||||
val (range, unbox, box) = data
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val unboxed = args.copyOf() as Array<Any?>
|
||||
for (index in range) {
|
||||
val method = unbox[index]
|
||||
val arg = args[index]
|
||||
// Note that arg may be null in case we're calling a $default method and it's an optional parameter of an inline class type
|
||||
unboxed[index] =
|
||||
if (method != null && arg != null) method.invoke(arg)
|
||||
else arg
|
||||
}
|
||||
|
||||
val result = caller.call(unboxed)
|
||||
|
||||
return box?.invoke(null, result) ?: result
|
||||
}
|
||||
|
||||
private fun Class<*>.getBoxMethod(): Method = try {
|
||||
getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getUnboxMethod().returnType)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
throw KotlinReflectionInternalError("No box method found in inline class: $this (calling $descriptor)")
|
||||
}
|
||||
|
||||
private fun Class<*>.getUnboxMethod(): Method = try {
|
||||
getDeclaredMethod("unbox" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
throw KotlinReflectionInternalError("No unbox method found in inline class: $this (calling $descriptor)")
|
||||
}
|
||||
|
||||
private fun KotlinType.toInlineClass(): Class<*>? {
|
||||
val descriptor = constructor.declarationDescriptor
|
||||
if (descriptor is ClassDescriptor && descriptor.isInline) {
|
||||
return descriptor.toJavaClass() ?: throw KotlinReflectionInternalError(
|
||||
"Class object for the class ${descriptor.name} cannot be found (classId=${descriptor.classId})"
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
isDefault: Boolean = false
|
||||
): Caller<M> {
|
||||
val needsInlineAwareCaller =
|
||||
descriptor.valueParameters.any { it.type.isInlineClassType() } ||
|
||||
descriptor.returnType?.isInlineClassType() == true ||
|
||||
(this !is BoundCaller && descriptor.extensionReceiverParameter?.type?.isInlineClassType() == true)
|
||||
return if (needsInlineAwareCaller) InlineClassAwareCaller(descriptor, this, isDefault) else this
|
||||
}
|
||||
+48
@@ -16057,6 +16057,44 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/call/inlineClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InlineClasses extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInlineClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldAccessors.kt")
|
||||
public void testFieldAccessors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/fieldAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionsAndConstructors.kt")
|
||||
public void testFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/functionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFieldInObject.kt")
|
||||
public void testJvmStaticFieldInObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFunction.kt")
|
||||
public void testJvmStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
|
||||
@@ -16101,6 +16139,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassFunctionsAndConstructors.kt")
|
||||
public void testInlineClassFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticInCompanionObject.kt")
|
||||
public void testJvmStaticInCompanionObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");
|
||||
@@ -16957,6 +17000,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassInSignature.kt")
|
||||
public void testInlineClassInSignature() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerGenericTypeArgument.kt")
|
||||
public void testInnerGenericTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
|
||||
|
||||
+48
@@ -17122,6 +17122,44 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/call/inlineClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InlineClasses extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInlineClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldAccessors.kt")
|
||||
public void testFieldAccessors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/fieldAccessors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionsAndConstructors.kt")
|
||||
public void testFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/functionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFieldInObject.kt")
|
||||
public void testJvmStaticFieldInObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticFunction.kt")
|
||||
public void testJvmStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
|
||||
@@ -17166,6 +17204,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassFunctionsAndConstructors.kt")
|
||||
public void testInlineClassFunctionsAndConstructors() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmStaticInCompanionObject.kt")
|
||||
public void testJvmStaticInCompanionObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");
|
||||
@@ -18022,6 +18065,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/genericArrayElementType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassInSignature.kt")
|
||||
public void testInlineClassInSignature() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerGenericTypeArgument.kt")
|
||||
public void testInnerGenericTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
|
||||
|
||||
Reference in New Issue
Block a user