JVM_IR KT-47939 use FunInterfaceConstructorReference as base class

This commit is contained in:
Dmitry Petrov
2021-12-07 17:30:56 +03:00
committed by TeamCityServer
parent 0ccd7a7e0c
commit 93713a9ad4
13 changed files with 158 additions and 42 deletions
@@ -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 {
@@ -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: <FUN_INTERFACE_TYPE>
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)))
}
}
}
@@ -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 ->
@@ -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}"
}
@@ -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
}
@@ -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");
}
}
@@ -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 {
@@ -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 {
@@ -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
@@ -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
@@ -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")
@@ -31,12 +31,6 @@ public class FunctionReference extends CallableReference implements FunctionBase
* fun useSuspend(f: suspend () -> Unit) {}
* useSuspend(::target)
* </pre></ul>
* <ul>3 - whether it is a synthetic <code>fun interface</code> constructor, i.e., <pre>
* fun interface KRunnable {
* fun run()
* }
* val kr: (() -> Unit) -> KRunnable = ::KRunnable
* </pre></ul>
* </li>
*/
@SinceKotlin(version = "1.4")
@@ -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