JVM_IR KT-47939 equality for fun interface constructor references
This commit is contained in:
committed by
TeamCityServer
parent
50b0dae786
commit
e179598457
+12
@@ -3585,11 +3585,23 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+48
-11
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
@@ -571,7 +572,16 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
}
|
||||
|
||||
private val adaptedReferenceOriginalTarget: IrFunction? = adapteeCall?.symbol?.owner
|
||||
private val isAdaptedReference = adaptedReferenceOriginalTarget != null
|
||||
private val isAdaptedFunInterfaceConstructorReference =
|
||||
callee.origin == IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR
|
||||
private val constructedFunInterfaceSymbol: IrClassSymbol? =
|
||||
if (isAdaptedFunInterfaceConstructorReference)
|
||||
callee.returnType.classOrNull
|
||||
?: throw AssertionError("Fun interface type expected: ${callee.returnType.render()}")
|
||||
else
|
||||
null
|
||||
private val isAdaptedReference =
|
||||
isAdaptedFunInterfaceConstructorReference || adaptedReferenceOriginalTarget != null
|
||||
|
||||
private val samInterface = samSuperType?.getClass()
|
||||
private val isKotlinFunInterface = samInterface != null && !samInterface.isFromJava()
|
||||
@@ -580,14 +590,15 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
isKotlinFunInterface && (isAdaptedReference || !isLambda)
|
||||
|
||||
private val superType =
|
||||
samSuperType ?: when {
|
||||
isLambda -> context.ir.symbols.lambdaClass
|
||||
useOptimizedSuperClass -> when {
|
||||
isAdaptedReference -> context.ir.symbols.adaptedFunctionReference
|
||||
else -> context.ir.symbols.functionReferenceImpl
|
||||
}
|
||||
else -> context.ir.symbols.functionReference
|
||||
}.defaultType
|
||||
samSuperType
|
||||
?: when {
|
||||
isLambda -> context.ir.symbols.lambdaClass
|
||||
useOptimizedSuperClass -> when {
|
||||
isAdaptedReference -> context.ir.symbols.adaptedFunctionReference
|
||||
else -> context.ir.symbols.functionReferenceImpl
|
||||
}
|
||||
else -> context.ir.symbols.functionReference
|
||||
}.defaultType
|
||||
|
||||
private val functionReferenceClass = context.irFactory.buildClass {
|
||||
setSourceRange(irFunctionReference)
|
||||
@@ -770,7 +781,17 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
if (boundReceiver != null) {
|
||||
call.putValueArgument(index++, generateBoundReceiver())
|
||||
}
|
||||
if (!isLambda && useOptimizedSuperClass) {
|
||||
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 = 4 << 1
|
||||
call.putValueArgument(index, irInt(8))
|
||||
} else if (!isLambda && useOptimizedSuperClass) {
|
||||
val callableReferenceTarget = adaptedReferenceOriginalTarget ?: callee
|
||||
val owner = calculateOwnerKClass(callableReferenceTarget.parent)
|
||||
call.putValueArgument(index++, kClassToJavaClass(owner))
|
||||
@@ -824,7 +845,12 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||
functionReferenceClass.symbol.defaultType
|
||||
)
|
||||
if (isLambda) createLambdaInvokeMethod() else createFunctionReferenceInvokeMethod(receiverVar)
|
||||
if (isLambda)
|
||||
createLambdaInvokeMethod()
|
||||
else if (isAdaptedFunInterfaceConstructorReference)
|
||||
createFunInterfaceConstructorInvokeMethod()
|
||||
else
|
||||
createFunctionReferenceInvokeMethod(receiverVar)
|
||||
}
|
||||
|
||||
// Inline the body of an anonymous function into the generated lambda subclass.
|
||||
@@ -835,6 +861,17 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
}
|
||||
valueParameters += valueParameterMap.values
|
||||
body = callee.moveBodyTo(this, valueParameterMap)
|
||||
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createFunInterfaceConstructorInvokeMethod() {
|
||||
val adapterValueParameter = callee.valueParameters.singleOrNull()
|
||||
?: throw AssertionError("Single value parameter expected: ${callee.render()}")
|
||||
val invokeValueParameter = adapterValueParameter.copyTo(this, index = 0)
|
||||
val valueParameterMap = mapOf(adapterValueParameter to invokeValueParameter)
|
||||
valueParameters = listOf(invokeValueParameter)
|
||||
body = callee.moveBodyTo(this, valueParameterMap)
|
||||
callee.body = null
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createFunctionReferenceInvokeMethod(receiver: IrValueDeclaration?) {
|
||||
|
||||
+1
@@ -223,6 +223,7 @@ private fun IrSimpleFunction.createMultifileDelegateIfNeeded(
|
||||
origin == JvmLoweredDeclarationOrigin.INLINE_LAMBDA ||
|
||||
origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ||
|
||||
origin == IrDeclarationOrigin.PROPERTY_DELEGATE ||
|
||||
origin == IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR ||
|
||||
// $annotations methods in the facade are only needed for const properties.
|
||||
(origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS &&
|
||||
(metadata as? MetadataSource.Property)?.isConst != true)
|
||||
|
||||
+4
-1
@@ -145,7 +145,10 @@ class ClassCodegen private constructor(
|
||||
val smap = context.getSourceMapper(irClass)
|
||||
// 1. Any method other than `<clinit>` can add a field and a `<clinit>` statement:
|
||||
for (method in irClass.declarations.filterIsInstance<IrFunction>()) {
|
||||
if (method.name.asString() != "<clinit>" && method.origin != JvmLoweredDeclarationOrigin.INLINE_LAMBDA) {
|
||||
if (method.name.asString() != "<clinit>" &&
|
||||
method.origin != JvmLoweredDeclarationOrigin.INLINE_LAMBDA &&
|
||||
method.origin != IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR
|
||||
) {
|
||||
generateMethod(method, smap)
|
||||
}
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// !LANGUAGE: +AllowKotlinFunInterfaceConstructorReference
|
||||
|
||||
// IGNORE_BACKEND: JVM
|
||||
// ^ unsupported in old JVM BE
|
||||
|
||||
// IGNORE_BACKEND: WASM
|
||||
// ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer
|
||||
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// ^ TypeError: tmp is not a function
|
||||
|
||||
// FILE: funInterfaceConstructorEquality.kt
|
||||
|
||||
val ks1: (() -> String) -> KSupplier<String> =
|
||||
::KSupplier
|
||||
|
||||
val ks11Foo = ks1(::foo)
|
||||
val ks21Foo = ks2(::foo)
|
||||
|
||||
fun box(): String {
|
||||
if (ks11Foo != ks12Foo)
|
||||
return "failed: ks11Foo != ks12Foo (same ctor, different source files)"
|
||||
if (ks11Foo != ks21Foo)
|
||||
return "failed: ks11Foo != ks21Foo (different ctors, same source file)"
|
||||
if (ks11Foo != ks22Foo)
|
||||
return "failed: ks11Foo != ks22Foo (different ctors, different source files)"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// FILE: KSupplier.kt
|
||||
|
||||
fun interface KSupplier<T> {
|
||||
fun get(): T
|
||||
}
|
||||
|
||||
fun foo() = "abc"
|
||||
|
||||
val ks2: (() -> String) -> KSupplier<String> =
|
||||
::KSupplier
|
||||
|
||||
val ks12Foo = ks1(::foo)
|
||||
val ks22Foo = ks2(::foo)
|
||||
Vendored
+2
-1
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +AllowKotlinFunInterfaceConstructorReference
|
||||
|
||||
// IGNORE_BACKEND: JVM
|
||||
// ^ feature supported in IR-based backends only
|
||||
// ^ unsupported in old JVM BE
|
||||
|
||||
fun interface KSupplier<T> {
|
||||
fun get(): T
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// !LANGUAGE: +AllowKotlinFunInterfaceConstructorReference
|
||||
|
||||
// DONT_TARGET_EXACT_BACKEND: JVM
|
||||
// ^ old JVM BE generates bogus code that fails in 'invoke', but works almost as expected in terms of equality
|
||||
|
||||
// IGNORE_BACKEND: WASM
|
||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||
|
||||
// FILE: funInterfaceConstructorEquality.kt
|
||||
|
||||
val ks1: (() -> String) -> KSupplier<String> =
|
||||
::KSupplier
|
||||
|
||||
val ks2: (() -> String) -> KSupplier<String> =
|
||||
::KSupplier
|
||||
|
||||
val kn1: (() -> Number) -> KSupplier<Number> =
|
||||
::KSupplier
|
||||
|
||||
fun box(): String {
|
||||
if (ks1 != ks2)
|
||||
return "Failed: ks1 != ks2 (same file, same SAM type)"
|
||||
if (ks1 != ks3)
|
||||
return "Failed: ks1 != ks3 (different file, same SAM type)"
|
||||
if (ks1 != kn1)
|
||||
return "Failed: ks1 != kn1 (same file, same SAM interface, different type arguments)"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// FILE: KSupplier.kt
|
||||
|
||||
fun interface KSupplier<T> {
|
||||
fun get(): T
|
||||
}
|
||||
|
||||
val ks3: (() -> String) -> KSupplier<String> =
|
||||
::KSupplier
|
||||
+6
@@ -3507,6 +3507,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
|
||||
+12
@@ -3585,11 +3585,23 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+5
@@ -3068,6 +3068,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FunInterfaceConstructor extends AbstractLightAnalysisModeTest {
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void ignoreFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void ignoreFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
|
||||
+12
@@ -2445,11 +2445,23 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+12
@@ -2487,11 +2487,23 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+10
@@ -2216,10 +2216,20 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/function")
|
||||
|
||||
@@ -31,6 +31,12 @@ public class FunctionReference extends CallableReference implements FunctionBase
|
||||
* fun useSuspend(f: suspend () -> Unit) {}
|
||||
* useSuspend(::target)
|
||||
* </pre></ul>
|
||||
* <ul>4 - 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")
|
||||
|
||||
+12
@@ -2517,11 +2517,23 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/funInterfaceConstructor"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructedObjectsEquality.kt")
|
||||
public void testFunInterfaceConstructedObjectsEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructedObjectsEquality.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructor.kt")
|
||||
public void testFunInterfaceConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("funInterfaceConstructorEquality.kt")
|
||||
public void testFunInterfaceConstructorEquality() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/funInterfaceConstructor/funInterfaceConstructorEquality.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user