diff --git a/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/J.java b/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/J.java new file mode 100644 index 00000000000..850e468878b --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/J.java @@ -0,0 +1,11 @@ +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; + } +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/K.kt b/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/K.kt new file mode 100644 index 00000000000..2e839c91830 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/K.kt @@ -0,0 +1,15 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun box(): String { + val f = J::foo + assertEquals( + listOf(javaClass(), javaClass(), javaClass>(), javaClass()), + f.parameters.map { it.type.javaType } + ) + assertEquals(javaClass(), f.returnType.javaType) + + assertEquals("01A2", f.call(J(0), intArrayOf(1), arrayOf("A"), 2)) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/J.java b/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/J.java new file mode 100644 index 00000000000..296781a4fef --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/J.java @@ -0,0 +1,5 @@ +public class J { + public static String foo(int x, int[] arr, Object[] arr2) { + return "" + x + arr[0] + arr2[0]; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/K.kt b/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/K.kt new file mode 100644 index 00000000000..240885da797 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/K.kt @@ -0,0 +1,12 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun box(): String { + val f = J::foo + assertEquals(listOf(Integer.TYPE, javaClass(), javaClass>()), f.parameters.map { it.type.javaType }) + assertEquals(javaClass(), f.returnType.javaType) + + assertEquals("01A", f.call(0, intArrayOf(1), arrayOf("A"))) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/array.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/array.kt new file mode 100644 index 00000000000..b0314032986 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/array.kt @@ -0,0 +1,30 @@ +// FULL_JDK + +import java.lang.reflect.GenericArrayType +import java.lang.reflect.TypeVariable +import java.lang.reflect.ParameterizedType +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun foo(strings: Array, integers: Array, objectArrays: Array>) {} + +fun bar(): Array> = null!! +class A { + fun baz(): Array = null!! +} + +fun box(): String { + assertEquals(javaClass>(), ::foo.parameters[0].type.javaType) + assertEquals(javaClass>(), ::foo.parameters[1].type.javaType) + assertEquals(javaClass>>(), ::foo.parameters[2].type.javaType) + + val g = ::bar.returnType.javaType + if (g !is GenericArrayType || g.genericComponentType !is ParameterizedType) + return "Fail: should be array of parameterized type, but was $g (${g.javaClass})" + + val h = A::baz.returnType.javaType + if (h !is GenericArrayType || h.genericComponentType !is TypeVariable<*>) + return "Fail: should be array of type variable, but was $h (${h.javaClass})" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/constructors.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/constructors.kt new file mode 100644 index 00000000000..e5aace1ff85 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/constructors.kt @@ -0,0 +1,20 @@ +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +class A(d: Double, s: String, parent: A?) { + class Nested(a: A) + inner class Inner(nested: Nested) +} + +fun box(): String { + assertEquals(listOf(java.lang.Double.TYPE, javaClass(), javaClass()), ::A.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass()), A::Nested.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass(), javaClass()), A::Inner.parameters.map { it.type.javaType }) + + assertEquals(javaClass(), ::A.returnType.javaType) + assertEquals(javaClass(), A::Nested.returnType.javaType) + assertEquals(javaClass(), A::Inner.returnType.javaType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/memberFunctions.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/memberFunctions.kt new file mode 100644 index 00000000000..f59b9135c27 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/memberFunctions.kt @@ -0,0 +1,21 @@ +import kotlin.platform.platformStatic as static +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +class A { + fun foo(t: Long?): Long = t!! +} + +object O { + static fun bar(a: A): String = "" +} + +fun box(): String { + assertEquals(listOf(javaClass(), javaClass()), A::foo.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass(), javaClass()), O::bar.parameters.map { it.type.javaType }) + + assertEquals(java.lang.Long.TYPE, A::foo.returnType.javaType) + assertEquals(javaClass(), O::bar.returnType.javaType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/overrideAnyWithPrimitive.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/overrideAnyWithPrimitive.kt new file mode 100644 index 00000000000..e8abbcb4823 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/overrideAnyWithPrimitive.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.jvm.* +import kotlin.test.* + +interface I { + fun foo(): Any +} + +class A : I { + override fun foo(): Int = 0 + fun bar(x: Long): Int = x.toInt() +} + +fun box(): String { + assertEquals(javaClass(), A::foo.returnType.javaType) + assertNotEquals(Integer.TYPE, A::foo.returnType.javaType) + + assertNotEquals(javaClass(), A::bar.returnType.javaType) + assertEquals(Integer.TYPE, A::bar.returnType.javaType) + + assertEquals(java.lang.Long.TYPE, A::bar.parameters.last().type.javaType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/parameterizedTypes.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/parameterizedTypes.kt new file mode 100644 index 00000000000..06e38a7b11c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/parameterizedTypes.kt @@ -0,0 +1,41 @@ +// FULL_JDK + +import java.lang.reflect.ParameterizedType +import kotlin.platform.platformStatic as static +import kotlin.reflect.* +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +class A(private var foo: List) + +object O { + private static var bar: List = listOf() +} + +fun topLevel(): List = listOf() +fun Any.extension(): List = listOf() + +fun assertGenericType(type: KType) { + val javaType = type.javaType + if (javaType !is ParameterizedType) { + throw AssertionError("Type should be a parameterized type, but was $javaType (${javaType.javaClass})") + } +} + +fun box(): String { + val foo = A::class.members.single { it.name == "foo" } as KMutableProperty<*> + assertGenericType(foo.returnType) + assertGenericType(foo.getter.returnType) + assertGenericType(foo.setter.parameters.last().type) + + val bar = O::class.members.single { it.name == "bar" } as KMutableProperty<*> + assertGenericType(bar.returnType) + assertGenericType(bar.getter.returnType) + assertGenericType(bar.setter.parameters.last().type) + + assertGenericType(::topLevel.returnType) + assertGenericType(Any::extension.returnType) + assertGenericType(::A.parameters.single().type) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/propertyAccessors.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/propertyAccessors.kt new file mode 100644 index 00000000000..ce3dba31df8 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/propertyAccessors.kt @@ -0,0 +1,24 @@ +import kotlin.platform.platformStatic as static +import kotlin.reflect.KMutableProperty +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +class A(private var foo: String) + +object O { + private static var bar: String = "" +} + +fun box(): String { + val foo = A::class.members.single { it.name == "foo" } as KMutableProperty<*> + assertEquals(listOf(javaClass()), foo.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass()), foo.getter.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass(), javaClass()), foo.setter.parameters.map { it.type.javaType }) + + val bar = O::class.members.single { it.name == "bar" } as KMutableProperty<*> + assertEquals(listOf(javaClass()), bar.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass()), bar.getter.parameters.map { it.type.javaType }) + assertEquals(listOf(javaClass(), javaClass()), bar.setter.parameters.map { it.type.javaType }) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/topLevelFunctions.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/topLevelFunctions.kt new file mode 100644 index 00000000000..a37124768b1 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/topLevelFunctions.kt @@ -0,0 +1,15 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun free(s: String): Int = s.length() + +fun Any.extension() {} + +fun box(): String { + assertEquals(java.lang.Integer.TYPE, ::free.returnType.javaType) + assertEquals(javaClass(), ::free.parameters.single().type.javaType) + + assertEquals(javaClass(), Any::extension.parameters.single().type.javaType) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/typeParameters.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/typeParameters.kt new file mode 100644 index 00000000000..9aa7b2c8126 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/typeParameters.kt @@ -0,0 +1,20 @@ +// FULL_JDK + +import java.lang.reflect.TypeVariable +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +class A { + fun foo(t: T) {} +} + +fun box(): String { + val f = A::foo + val t = f.parameters.last().type.javaType + if (t !is TypeVariable<*>) return "Fail, t should be a type variable: $t" + + assertEquals("T", t.name) + assertEquals("A", (t.genericDeclaration as Class<*>).name) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/unit.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/unit.kt new file mode 100644 index 00000000000..e988c125f94 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/unit.kt @@ -0,0 +1,21 @@ +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun foo(unitParam: Unit, nullableUnitParam: Unit?): Unit {} + +var bar: Unit = Unit + +fun box(): String { + assert(javaClass() != java.lang.Void.TYPE) + + assertEquals(javaClass(), ::foo.parameters[0].type.javaType) + assertEquals(javaClass(), ::foo.parameters[1].type.javaType) + assertEquals(java.lang.Void.TYPE, ::foo.returnType.javaType) + + assertEquals(javaClass(), ::bar.returnType.javaType) + assertEquals(javaClass(), ::bar.getter.returnType.javaType) + assertEquals(javaClass(), ::bar.setter.parameters.single().type.javaType) + assertEquals(java.lang.Void.TYPE, ::bar.setter.returnType.javaType) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 4ea0806b7a9..aefdc3fd4f7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -267,6 +267,18 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava/reflection"), Pattern.compile("^([^\\.]+)$"), true); } + @TestMetadata("callInstanceJavaMethod") + public void testCallInstanceJavaMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/callInstanceJavaMethod/"); + doTestWithJava(fileName); + } + + @TestMetadata("callStaticJavaMethod") + public void testCallStaticJavaMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/callStaticJavaMethod/"); + doTestWithJava(fileName); + } + @TestMetadata("functionReferenceErasedToKFunction") public void testFunctionReferenceErasedToKFunction() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/functionReferenceErasedToKFunction/"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 2c035469e77..519199607c1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3359,6 +3359,69 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt"); doTestWithStdlib(fileName); } + + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Types extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInTypes() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("array.kt") + public void testArray() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/array.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("constructors.kt") + public void testConstructors() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/constructors.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("memberFunctions.kt") + public void testMemberFunctions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/memberFunctions.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("overrideAnyWithPrimitive.kt") + public void testOverrideAnyWithPrimitive() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/overrideAnyWithPrimitive.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("parameterizedTypes.kt") + public void testParameterizedTypes() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/parameterizedTypes.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("propertyAccessors.kt") + public void testPropertyAccessors() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/propertyAccessors.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("topLevelFunctions.kt") + public void testTopLevelFunctions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/topLevelFunctions.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("typeParameters.kt") + public void testTypeParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/typeParameters.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("unit.kt") + public void testUnit() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types/unit.kt"); + doTestWithStdlib(fileName); + } + } } @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny") 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 ebf0cdddf86..03b7a3c41d3 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -17,20 +17,23 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Member +import java.lang.reflect.Modifier +import java.lang.reflect.Type import java.lang.reflect.Constructor as ReflectConstructor import java.lang.reflect.Field as ReflectField import java.lang.reflect.Method as ReflectMethod -internal sealed class FunctionCaller( - private val expectedArgumentNumber: Int -) { +internal abstract class FunctionCaller { abstract val member: Member + abstract val returnType: Type + abstract val parameterTypes: List + abstract fun call(args: Array<*>): Any? protected open fun checkArguments(args: Array<*>) { - if (expectedArgumentNumber != args.size()) { - throw IllegalArgumentException("Callable expects $expectedArgumentNumber arguments, but ${args.size()} were provided.") + if (parameterTypes.size() != args.size()) { + throw IllegalArgumentException("Callable expects ${parameterTypes.size()} arguments, but ${args.size()} were provided.") } } @@ -40,9 +43,16 @@ internal sealed class FunctionCaller( } } - class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller(constructor.parameterTypes.size()) { + class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller() { override val member: Member get() = constructor + override val returnType = constructor.declaringClass + + override val parameterTypes = + if (returnType.declaringClass == null || Modifier.isStatic(returnType.modifiers)) + constructor.genericParameterTypes.toList() + else listOf(returnType.declaringClass, *constructor.genericParameterTypes) + override fun call(args: Array<*>): Any? { checkArguments(args) return constructor.newInstance(*args) @@ -51,10 +61,17 @@ internal sealed class FunctionCaller( abstract class Method( val method: ReflectMethod, - requiresInstance: Boolean - ) : FunctionCaller(method.parameterTypes.size() + (if (requiresInstance) 1 else 0)) { + private val requiresInstance: Boolean + ) : FunctionCaller() { override val member: Member get() = method - private val isVoidMethod = method.returnType == Void.TYPE + + override val returnType = method.genericReturnType + + override val parameterTypes = + if (requiresInstance) listOf(method.declaringClass, *method.genericParameterTypes) + else method.genericParameterTypes.toList() + + private val isVoidMethod = returnType == Void.TYPE protected fun callMethod(instance: Any?, args: Array<*>): Any? { val result = method.invoke(instance, *args) @@ -86,14 +103,19 @@ internal sealed class FunctionCaller( } } - abstract class FieldAccessor(val field: ReflectField, expectedArgumentNumber: Int) : FunctionCaller(expectedArgumentNumber) { + abstract class FieldAccessor(val field: ReflectField) : FunctionCaller() { override val member: Member get() = field } abstract class FieldGetter( field: ReflectField, private val requiresInstance: Boolean - ) : FieldAccessor(field, if (requiresInstance) 1 else 0) { + ) : FieldAccessor(field) { + override val returnType = field.genericType + + override val parameterTypes = + if (requiresInstance) listOf(field.declaringClass) else listOf() + override fun call(args: Array<*>): Any? { checkArguments(args) return field.get(if (requiresInstance) args.first() else null) @@ -104,7 +126,13 @@ internal sealed class FunctionCaller( field: ReflectField, private val notNull: Boolean, private val requiresInstance: Boolean - ) : FieldAccessor(field, if (requiresInstance) 2 else 1) { + ) : FieldAccessor(field) { + override val returnType: Type get() = Void.TYPE + + override val parameterTypes = + if (requiresInstance) listOf(field.declaringClass, field.genericType) + else listOf(field.genericType) + override fun checkArguments(args: Array<*>) { super.checkArguments(args) if (notNull && args.last() == null) { 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 4ff5b02074d..77f71e9edc7 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -36,15 +36,15 @@ interface KCallableImpl : KCallable, KAnnotatedElementImpl { var index = 0 if (descriptor.dispatchReceiverParameter != null) { - result.add(KParameterImpl(index++) { descriptor.dispatchReceiverParameter!! }) + result.add(KParameterImpl(this, index++) { descriptor.dispatchReceiverParameter!! }) } if (descriptor.extensionReceiverParameter != null) { - result.add(KParameterImpl(index++) { descriptor.extensionReceiverParameter!! }) + result.add(KParameterImpl(this, index++) { descriptor.extensionReceiverParameter!! }) } for (i in descriptor.valueParameters.indices) { - result.add(KParameterImpl(index++) { descriptor.valueParameters[i] }) + result.add(KParameterImpl(this, index++) { descriptor.valueParameters[i] }) } result.trimToSize() @@ -52,7 +52,7 @@ interface KCallableImpl : KCallable, KAnnotatedElementImpl { } override val returnType: KType - get() = KTypeImpl(descriptor.returnType!!) + get() = KTypeImpl(descriptor.returnType!!) { caller.returnType } @suppress("UNCHECKED_CAST") override fun call(vararg args: Any?): R = reflectionCall { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt index 3688b0e1c37..d8062b114f8 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt @@ -23,8 +23,9 @@ import kotlin.reflect.KParameter import kotlin.reflect.KType class KParameterImpl( + val callable: KCallableImpl<*>, override val index: Int, - private val computeDescriptor: () -> ParameterDescriptor + computeDescriptor: () -> ParameterDescriptor ) : KParameter, KAnnotatedElementImpl { private val descriptor: ParameterDescriptor by ReflectProperties.lazySoft(computeDescriptor) @@ -38,5 +39,5 @@ class KParameterImpl( } override val type: KType - get() = KTypeImpl(descriptor.getType()) + get() = KTypeImpl(descriptor.type) { callable.caller.parameterTypes[index] } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt index 8c22b4d6909..7cf27288a0a 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -17,9 +17,15 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.types.JetType +import java.lang.reflect.Type import kotlin.reflect.KType -class KTypeImpl(val type: JetType) : KType { +class KTypeImpl( + val type: JetType, + computeJavaType: () -> Type +) : KType { + internal val javaType: Type by ReflectProperties.lazySoft(computeJavaType) + override val isMarkedNullable: Boolean get() = type.isMarkedNullable } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt index e3ec39f3961..b6e2118fab0 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -16,10 +16,7 @@ package kotlin.reflect.jvm -import java.lang.reflect.Constructor -import java.lang.reflect.Field -import java.lang.reflect.Method -import java.lang.reflect.Modifier +import java.lang.reflect.* import kotlin.jvm.internal.Intrinsic import kotlin.reflect.* import kotlin.reflect.jvm.internal.* @@ -87,6 +84,15 @@ public val KFunction.javaConstructor: Constructor? } +/** + * Returns a Java [Type] instance corresponding to the given Kotlin type. + * Note that one Kotlin type may correspond to different JVM types depending on where it appears. For example, [Unit] corresponds to + * the JVM class [Unit] when it's the type of a parameter, or to `void` when it's the return type of a function. + */ +public val KType.javaType: Type + get() = (this as KTypeImpl).javaType + + // Java reflection -> Kotlin reflection