diff --git a/compiler/testData/codegen/box/reflection/functions/instanceOfFunction.kt b/compiler/testData/codegen/box/reflection/functions/instanceOfFunction.kt new file mode 100644 index 00000000000..473b83d43de --- /dev/null +++ b/compiler/testData/codegen/box/reflection/functions/instanceOfFunction.kt @@ -0,0 +1,36 @@ +// WITH_REFLECT +// FILE: FromJava.java + +import kotlin.reflect.KCallable; +import kotlin.jvm.functions.Function1; +import kotlin.jvm.functions.Function2; +import kotlin.jvm.functions.Function3; + +public class FromJava { + public static String test(KCallable x) { + if (!(x instanceof Function1)) return "Fail 6"; + if (!(x instanceof Function2)) return "Fail 7"; + if (!(x instanceof Function3)) return "Fail 8"; + return "OK"; + } +} + +// FILE: test.kt + +class Foo { + fun bar(x: Int): Int = x + 1 +} + +fun box(): String { + val bar = Foo::class.members.single { it.name == "bar" } + + if (bar is Function1<*, *>) return "Fail 1" + if (bar !is Function2<*, *, *>) return "Fail 2" + if (bar is Function3<*, *, *, *>) return "Fail 3" + + bar as? Function2 ?: return "Fail 4" + + if (bar(Foo(), 42) != 43) return "Fail 5" + + return FromJava.test(bar) +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 263c1038daa..3902b4b94a5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12270,6 +12270,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("instanceOfFunction.kt") + public void testInstanceOfFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/instanceOfFunction.kt"); + doTest(fileName); + } + @TestMetadata("javaClassGetFunctions.kt") public void testJavaClassGetFunctions() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/javaClassGetFunctions.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 54ba74c8d13..502daa64d9e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -29,15 +29,18 @@ internal abstract class FunctionCaller( internal val instanceClass: Class<*>?, valueParameterTypes: Array ) { - internal val parameterTypes: List = + val parameterTypes: List = instanceClass?.let { listOf(it, *valueParameterTypes) } ?: valueParameterTypes.toList() + val arity: Int + get() = parameterTypes.size + abstract fun call(args: Array<*>): Any? protected open fun checkArguments(args: Array<*>) { - if (parameterTypes.size != args.size) { - throw IllegalArgumentException("Callable expects ${parameterTypes.size} arguments, but ${args.size} were provided.") + if (arity != args.size) { + throw IllegalArgumentException("Callable expects $arity arguments, but ${args.size} were provided.") } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionWithAllInvokes.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionWithAllInvokes.kt new file mode 100644 index 00000000000..2ae761a6411 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionWithAllInvokes.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.jvm.internal + +import kotlin.reflect.KCallable + +internal interface FunctionWithAllInvokes : + // (0..22).forEach { n -> println("Function$n<" + (0..n).joinToString { "Any?" } + ">,") } + Function0, + Function1, + Function2, + Function3, + Function4, + Function5, + Function6, + Function7, + Function8, + Function9, + Function10, + Function11, + Function12, + Function13, + Function14, + Function15, + Function16, + Function17, + Function18, + Function19, + Function20, + Function21, + Function22, + KCallable +{ + // (0..22).forEach { n -> println("override fun invoke(" + (1..n).joinToString { "p$it: Any?" } + "): Any? = call(" + (1..n).joinToString { "p$it" } + ")") } + override fun invoke(): Any? = call() + override fun invoke(p1: Any?): Any? = call(p1) + override fun invoke(p1: Any?, p2: Any?): Any? = call(p1, p2) + override fun invoke(p1: Any?, p2: Any?, p3: Any?): Any? = call(p1, p2, p3) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?): Any? = call(p1, p2, p3, p4) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?): Any? = call(p1, p2, p3, p4, p5) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?): Any? = call(p1, p2, p3, p4, p5, p6) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?, p21: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21) + override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?, p21: Any?, p22: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22) +} 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 ed23ed0f556..d1917dd649e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -33,7 +33,7 @@ internal class KFunctionImpl private constructor( name: String, private val signature: String, descriptorInitialValue: FunctionDescriptor? -) : KFunction, KCallableImpl, FunctionImpl { +) : KFunction, KCallableImpl, FunctionImpl, FunctionWithAllInvokes { constructor(container: KDeclarationContainerImpl, name: String, signature: String) : this(container, name, signature, null) constructor(container: KDeclarationContainerImpl, descriptor: FunctionDescriptor) : this( @@ -103,11 +103,7 @@ internal class KFunctionImpl private constructor( } } - override fun getArity(): Int { - return descriptor.valueParameters.size + - (if (descriptor.dispatchReceiverParameter != null) 1 else 0) + - (if (descriptor.extensionReceiverParameter != null) 1 else 0) - } + override fun getArity() = caller.arity override val isInline: Boolean get() = descriptor.isInline