diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 09a6a3ea139..b6f4e2ba4b8 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -3603,6 +3603,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + @Test + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @Test + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } + @Test @TestMetadata("funInterfaceConstructorThrowsNpe.kt") public void testFunInterfaceConstructorThrowsNpe() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index c9e094c20e3..27ba0150da6 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -593,6 +593,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) samSuperType ?: when { isLambda -> context.ir.symbols.lambdaClass + isAdaptedFunInterfaceConstructorReference -> context.ir.symbols.funInterfaceConstructorReferenceClass useOptimizedSuperClass -> when { isAdaptedReference -> context.ir.symbols.adaptedFunctionReference else -> context.ir.symbols.functionReferenceImpl @@ -743,22 +744,29 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) } // Super constructor: + // - For fun interface constructor references, super class is kotlin.jvm.internal.FunInterfaceConstructorReference + // with single constructor 'public FunInterfaceConstructorReference(Class funInterface)' // - For SAM references, the super class is Any // - For lambdas, accepts arity // - For optimized function references (1.4+), accepts: // arity, [receiver], owner, name, signature, flags // - For unoptimized function references, accepts: // arity, [receiver] - val constructor = if (samSuperType != null) { - context.irBuiltIns.anyClass.owner.constructors.single() - } else { - val expectedArity = - if (isLambda && !isAdaptedReference) 1 - else 1 + (if (boundReceiver != null) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0) - superType.getClass()!!.constructors.single { - it.valueParameters.size == expectedArity + val constructor = + when { + isAdaptedFunInterfaceConstructorReference -> + context.ir.symbols.funInterfaceConstructorReferenceClass.owner.constructors.single() + samSuperType != null -> + context.irBuiltIns.anyClass.owner.constructors.single() + else -> { + val expectedArity = + if (isLambda && !isAdaptedReference) 1 + else 1 + (if (boundReceiver != null) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0) + superType.getClass()!!.constructors.single { + it.valueParameters.size == expectedArity + } + } } - } body = context.createJvmIrBuilder(symbol).run { irBlockBody(startOffset, endOffset) { @@ -776,28 +784,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) call: IrFunctionAccessExpression, generateBoundReceiver: IrBuilder.() -> IrExpression ) { - var index = 0 - call.putValueArgument(index++, irInt(argumentTypes.size + if (irFunctionReference.isSuspend) 1 else 0)) - if (boundReceiver != null) { - call.putValueArgument(index++, generateBoundReceiver()) - } if (isAdaptedFunInterfaceConstructorReference) { - val owner = kClassReference(constructedFunInterfaceSymbol!!.owner.defaultType) - // owner: - call.putValueArgument(index++, kClassToJavaClass(owner)) - // name: "" - call.putValueArgument(index++, irString("")) - // signature: "" - call.putValueArgument(index++, irString("")) - // flags: 8 = 3 << 1 - call.putValueArgument(index, irInt(8)) - } else if (!isLambda && useOptimizedSuperClass) { - val callableReferenceTarget = adaptedReferenceOriginalTarget ?: callee - val owner = calculateOwnerKClass(callableReferenceTarget.parent) - call.putValueArgument(index++, kClassToJavaClass(owner)) - call.putValueArgument(index++, irString(callableReferenceTarget.originalName.asString())) - call.putValueArgument(index++, generateSignature(callableReferenceTarget.symbol)) - call.putValueArgument(index, irInt(getFunctionReferenceFlags(callableReferenceTarget))) + val funInterfaceKClassRef = kClassReference(constructedFunInterfaceSymbol!!.owner.defaultType) + val funInterfaceJavaClassRef = kClassToJavaClass(funInterfaceKClassRef) + call.putValueArgument(0, funInterfaceJavaClassRef) + } else { + var index = 0 + call.putValueArgument(index++, irInt(argumentTypes.size + if (irFunctionReference.isSuspend) 1 else 0)) + if (boundReceiver != null) { + call.putValueArgument(index++, generateBoundReceiver()) + } + if (!isLambda && useOptimizedSuperClass) { + val callableReferenceTarget = adaptedReferenceOriginalTarget ?: callee + val owner = calculateOwnerKClass(callableReferenceTarget.parent) + call.putValueArgument(index++, kClassToJavaClass(owner)) + call.putValueArgument(index++, irString(callableReferenceTarget.originalName.asString())) + call.putValueArgument(index++, generateSignature(callableReferenceTarget.symbol)) + call.putValueArgument(index, irInt(getFunctionReferenceFlags(callableReferenceTarget))) + } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 157cf67f56f..a5d6260d5c9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -377,6 +377,14 @@ class JvmSymbols( } } + val funInterfaceConstructorReferenceClass = + createClass(FqName("kotlin.jvm.internal.FunInterfaceConstructorReference"), classModality = Modality.OPEN) { irClass -> + irClass.superTypes = listOf(irBuiltIns.anyType) + irClass.addConstructor().also { irConstructor -> + irConstructor.addValueParameter("funInterface", javaLangClass.starProjectedType) + } + } + fun getFunction(parameterCount: Int): IrClassSymbol = irBuiltIns.functionN(parameterCount).symbol private val jvmFunctionClasses = storageManager.createMemoizedFunction { n: Int -> diff --git a/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt b/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt new file mode 100644 index 00000000000..d8f9c32a118 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt @@ -0,0 +1,24 @@ +// !LANGUAGE: +KotlinFunInterfaceConstructorReference + +// DONT_TARGET_EXACT_BACKEND: JVM +// ^ old JVM BE generates bogus code + +// IGNORE_BACKEND: JS +// ^ Failed: kr is class Function1 + +// WITH_REFLECT + +import kotlin.reflect.KFunction + +fun interface KRunnable { + fun run() +} + +val kr = ::KRunnable // : KFunction1<() -> Unit, KRunnable> + +fun box(): String { + return if (kr is KFunction<*>) + "OK" + else + "Failed: kr is ${kr::class}" +} diff --git a/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt b/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt new file mode 100644 index 00000000000..ee4b554f115 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +KotlinFunInterfaceConstructorReference + +// IGNORE_BACKEND: JVM +// ^ unsupported in old JVM BE + +fun interface KRunnable { + fun run() +} + +val kr = ::KRunnable // : KFunction1<() -> Unit, KRunnable> + +fun box(): String { + var test = "Failed" + kr { test = "OK" }.run() + return test +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 335e4d6a052..41744d4d3a7 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -3520,9 +3520,9 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } @Test - @TestMetadata("funInterfaceConstructorThrowsNpe.kt") - public void testFunInterfaceConstructorThrowsNpe() throws Exception { - runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorThrowsNpe.kt"); + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); } } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index c3435b7b27e..f781538d11c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -3603,6 +3603,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + @Test + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @Test + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } + @Test @TestMetadata("funInterfaceConstructorThrowsNpe.kt") public void testFunInterfaceConstructorThrowsNpe() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 0389bf697f1..132c93dba74 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -3078,9 +3078,9 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt"); } - @TestMetadata("funInterfaceConstructorThrowsNpe.kt") - public void ignoreFunInterfaceConstructorThrowsNpe() throws Exception { - runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorThrowsNpe.kt"); + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void ignoreFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); } private void runTest(String testDataFilePath) throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index a65b165fffa..63813429285 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -2462,6 +2462,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testFunInterfaceConstructorEquality() throws Exception { runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + + @Test + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @Test + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 569ba50fa52..b6c164e1856 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -2504,6 +2504,18 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testFunInterfaceConstructorEquality() throws Exception { runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + + @Test + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @Test + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index c66a4bb8db0..3e28ab5f07b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -2230,6 +2230,16 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest public void testFunInterfaceConstructorEquality() throws Exception { runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } } @TestMetadata("compiler/testData/codegen/box/callableReference/function") diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/FunctionReference.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/FunctionReference.java index 0c58b40f2d6..1d3285d28d3 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/FunctionReference.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/FunctionReference.java @@ -31,12 +31,6 @@ public class FunctionReference extends CallableReference implements FunctionBase * fun useSuspend(f: suspend () -> Unit) {} * useSuspend(::target) * - * * */ @SinceKotlin(version = "1.4") diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java index 32f3a3f81eb..4e23c50baed 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java @@ -2534,6 +2534,18 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { public void testFunInterfaceConstructorEquality() throws Exception { runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt"); } + + @Test + @TestMetadata("funInterfaceConstructorIsKFunction.kt") + public void testFunInterfaceConstructorIsKFunction() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorIsKFunction.kt"); + } + + @Test + @TestMetadata("funInterfaceConstructorOfImplicitKFunctionType.kt") + public void testFunInterfaceConstructorOfImplicitKFunctionType() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorOfImplicitKFunctionType.kt"); + } } @Nested