[K/N] Fix work with adapted function references

Their parsing was totally incorrect for K2, and sometimes incorrect for
K1. After this commit it uses same code as for JVM.

^KT-55462
This commit is contained in:
Pavel Kunyavskiy
2023-01-24 12:42:19 +01:00
committed by Space Team
parent 9a693fa967
commit cb655d2d37
25 changed files with 292 additions and 32 deletions
@@ -3826,6 +3826,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -463,6 +463,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
private val useOptimizedSuperClass =
context.state.generateOptimizedCallableReferenceSuperClasses
// This code is partially duplicated in IrUtils getAdapteeFromAdaptedForReferenceFunction
// The difference is utils version supports ReturnableBlock, but returns called function instead of call node.
private val adapteeCall: IrFunctionAccessExpression? =
if (callee.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
@@ -1368,3 +1368,24 @@ val IrFunction.isValueClassTypedEquals: Boolean
&& contextReceiverParametersCount == 0 && extensionReceiverParameter == null
&& (parentClass.isValue)
}
// This code is partially duplicated in jvm FunctionReferenceLowering::adapteeCall
// The difference is jvm version doesn't support ReturnableBlock, but returns call node instead of called function.
fun IrFunction.getAdapteeFromAdaptedForReferenceFunction() : IrFunction? {
if (origin != IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) return null
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
// applied to a either a call or ReturnableBlock produced from that call inlining.
// That call's target is the original function which we need to get.
fun unknownStructure(): Nothing = throw UnsupportedOperationException("Unknown structure of ADAPTER_FOR_CALLABLE_REFERENCE: ${dump()}")
val call = when (val statement = body?.statements?.singleOrNull() ?: unknownStructure()) {
is IrTypeOperatorCall -> {
if (statement.operator != IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) unknownStructure()
statement.argument
}
is IrReturn -> statement.value
else -> statement
}
if (call is IrReturnableBlock) return (call.inlineFunctionSymbol ?: unknownStructure()).owner
if (call !is IrFunctionAccessExpression) { unknownStructure() }
return call.symbol.owner
}
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -0,0 +1,163 @@
// !LANGUAGE: +SuspendConversion
// WITH_STDLIB
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND: JVM, JVM_IR
fun checkEqual(x: Any, y: Any) {
if (x != y || y != x) throw AssertionError("$x and $y should be equal")
if (x.hashCode() != y.hashCode()) throw AssertionError("$x and $y should have the same hash code")
}
inline fun inlineF(a:Int, vararg b: String, c: Int = 0) = 0
inline fun <reified T> inlineReifiedF(a: T, vararg b: String, c: Int = 0) = 0
fun normalF(a:Int, vararg b: String, c: Int = 0) = 0
fun noConversion(ref: (Int, Array<String>, Int) -> Int) = ref
fun suspendConversion(ref: suspend (Int, Array<String>, Int) -> Int) = ref
fun unitConversion(ref: (Int, Array<String>, Int) -> Unit) = ref
fun defaultConversion(ref: (Int, Array<String>) -> Int) = ref
fun varargConversion(ref: (Int, String, Int) -> Int) = ref
fun suspendAndUnitConversion(ref: suspend (Int, Array<String>, Int) -> Unit) = ref
fun suspendAndDefaultConversion(ref: suspend (Int, Array<String>) -> Int) = ref
fun suspendAndVarargConversion(ref: suspend (Int, String, Int) -> Int) = ref
fun unitAndDefaultConversion(ref: (Int, Array<String>) -> Unit) = ref
fun unitAndVarargConversion(ref: (Int, String, Int) -> Unit) = ref
fun defaultAndVarargConversion(ref: (Int, String) -> Int) = ref
fun allExceptSuspendConversion(ref: (Int, String) -> Unit) = ref
fun allExceptUnitConversion(ref: suspend (Int, String) -> Int) = ref
fun allExceptVarargConversion(ref: suspend (Int, Array<String>) -> Unit) = ref
fun allExceptDefaultConversion(ref: suspend (Int, String, Int) -> Unit) = ref
fun allConversions(ref: suspend (Int, String) -> Unit) = ref
fun testNormal() {
checkEqual(noConversion(::normalF), noConversion(::normalF))
checkEqual(suspendConversion(::normalF), suspendConversion(::normalF))
checkEqual(unitConversion(::normalF), unitConversion(::normalF))
checkEqual(defaultConversion(::normalF), defaultConversion(::normalF))
checkEqual(varargConversion(::normalF), varargConversion(::normalF))
checkEqual(suspendAndUnitConversion(::normalF), suspendAndUnitConversion(::normalF))
checkEqual(suspendAndDefaultConversion(::normalF), suspendAndDefaultConversion(::normalF))
checkEqual(suspendAndVarargConversion(::normalF), suspendAndVarargConversion(::normalF))
checkEqual(unitAndDefaultConversion(::normalF), unitAndDefaultConversion(::normalF))
checkEqual(unitAndVarargConversion(::normalF), unitAndVarargConversion(::normalF))
checkEqual(defaultAndVarargConversion(::normalF), defaultAndVarargConversion(::normalF))
checkEqual(allExceptSuspendConversion(::normalF), allExceptSuspendConversion(::normalF))
checkEqual(allExceptUnitConversion(::normalF), allExceptUnitConversion(::normalF))
checkEqual(allExceptVarargConversion(::normalF), allExceptVarargConversion(::normalF))
checkEqual(allExceptDefaultConversion(::normalF), allExceptDefaultConversion(::normalF))
checkEqual(allConversions(::normalF), allConversions(::normalF))
}
fun testInline() {
checkEqual(noConversion(::inlineF), noConversion(::inlineF))
checkEqual(suspendConversion(::inlineF), suspendConversion(::inlineF))
checkEqual(unitConversion(::inlineF), unitConversion(::inlineF))
checkEqual(defaultConversion(::inlineF), defaultConversion(::inlineF))
checkEqual(varargConversion(::inlineF), varargConversion(::inlineF))
checkEqual(suspendAndUnitConversion(::inlineF), suspendAndUnitConversion(::inlineF))
checkEqual(suspendAndDefaultConversion(::inlineF), suspendAndDefaultConversion(::inlineF))
checkEqual(suspendAndVarargConversion(::inlineF), suspendAndVarargConversion(::inlineF))
checkEqual(unitAndDefaultConversion(::inlineF), unitAndDefaultConversion(::inlineF))
checkEqual(unitAndVarargConversion(::inlineF), unitAndVarargConversion(::inlineF))
checkEqual(defaultAndVarargConversion(::inlineF), defaultAndVarargConversion(::inlineF))
checkEqual(allExceptSuspendConversion(::inlineF), allExceptSuspendConversion(::inlineF))
checkEqual(allExceptUnitConversion(::inlineF), allExceptUnitConversion(::inlineF))
checkEqual(allExceptVarargConversion(::inlineF), allExceptVarargConversion(::inlineF))
checkEqual(allExceptDefaultConversion(::inlineF), allExceptDefaultConversion(::inlineF))
checkEqual(allConversions(::inlineF), allConversions(::inlineF))
}
fun testInlineReifined() {
checkEqual(noConversion(::inlineReifiedF), noConversion(::inlineReifiedF))
checkEqual(suspendConversion(::inlineReifiedF), suspendConversion(::inlineReifiedF))
checkEqual(unitConversion(::inlineReifiedF), unitConversion(::inlineReifiedF))
checkEqual(defaultConversion(::inlineReifiedF), defaultConversion(::inlineReifiedF))
checkEqual(varargConversion(::inlineReifiedF), varargConversion(::inlineReifiedF))
checkEqual(suspendAndUnitConversion(::inlineReifiedF), suspendAndUnitConversion(::inlineReifiedF))
checkEqual(suspendAndDefaultConversion(::inlineReifiedF), suspendAndDefaultConversion(::inlineReifiedF))
checkEqual(suspendAndVarargConversion(::inlineReifiedF), suspendAndVarargConversion(::inlineReifiedF))
checkEqual(unitAndDefaultConversion(::inlineReifiedF), unitAndDefaultConversion(::inlineReifiedF))
checkEqual(unitAndVarargConversion(::inlineReifiedF), unitAndVarargConversion(::inlineReifiedF))
checkEqual(defaultAndVarargConversion(::inlineReifiedF), defaultAndVarargConversion(::inlineReifiedF))
checkEqual(allExceptSuspendConversion(::inlineReifiedF), allExceptSuspendConversion(::inlineReifiedF))
checkEqual(allExceptUnitConversion(::inlineReifiedF), allExceptUnitConversion(::inlineReifiedF))
checkEqual(allExceptVarargConversion(::inlineReifiedF), allExceptVarargConversion(::inlineReifiedF))
checkEqual(allExceptDefaultConversion(::inlineReifiedF), allExceptDefaultConversion(::inlineReifiedF))
checkEqual(allConversions(::inlineReifiedF), allConversions(::inlineReifiedF))
}
fun box() : String {
testNormal()
testInline()
testInlineReifined()
val allRefs = mapOf(
"noConversionNormal" to noConversion(::normalF),
"suspendConversionNormal" to suspendConversion(::normalF),
"unitConversionNormal" to unitConversion(::normalF),
"defaultConversionNormal" to defaultConversion(::normalF),
"varargConversionNormal" to varargConversion(::normalF),
"suspendAndUnitConversionNormal" to suspendAndUnitConversion(::normalF),
"suspendAndDefaultConversionNormal" to suspendAndDefaultConversion(::normalF),
"suspendAndVarargConversionNormal" to suspendAndVarargConversion(::normalF),
"unitAndDefaultConversionNormal" to unitAndDefaultConversion(::normalF),
"unitAndVarargConversionNormal" to unitAndVarargConversion(::normalF),
"defaultAndVarargConversionNormal" to defaultAndVarargConversion(::normalF),
"allExceptSuspendConversionNormal" to allExceptSuspendConversion(::normalF),
"allExceptUnitConversionNormal" to allExceptUnitConversion(::normalF),
"allExceptVarargConversionNormal" to allExceptVarargConversion(::normalF),
"allExceptDefaultConversionNormal" to allExceptDefaultConversion(::normalF),
"allConversionsNormal" to allConversions(::normalF),
"noConversionInline" to noConversion(::inlineF),
"suspendConversionInline" to suspendConversion(::inlineF),
"unitConversionInline" to unitConversion(::inlineF),
"defaultConversionInline" to defaultConversion(::inlineF),
"varargConversionInline" to varargConversion(::inlineF),
"suspendAndUnitConversionInline" to suspendAndUnitConversion(::inlineF),
"suspendAndDefaultConversionInline" to suspendAndDefaultConversion(::inlineF),
"suspendAndVarargConversionInline" to suspendAndVarargConversion(::inlineF),
"unitAndDefaultConversionInline" to unitAndDefaultConversion(::inlineF),
"unitAndVarargConversionInline" to unitAndVarargConversion(::inlineF),
"defaultAndVarargConversionInline" to defaultAndVarargConversion(::inlineF),
"allExceptSuspendConversionInline" to allExceptSuspendConversion(::inlineF),
"allExceptUnitConversionInline" to allExceptUnitConversion(::inlineF),
"allExceptVarargConversionInline" to allExceptVarargConversion(::inlineF),
"allExceptDefaultConversionInline" to allExceptDefaultConversion(::inlineF),
"allConversionsInline" to allConversions(::inlineF),
"noConversionInlineReified" to noConversion(::inlineReifiedF),
"suspendConversionInlineReified" to suspendConversion(::inlineReifiedF),
"unitConversionInlineReified" to unitConversion(::inlineReifiedF),
"defaultConversionInlineReified" to defaultConversion(::inlineReifiedF),
"varargConversionInlineReified" to varargConversion(::inlineReifiedF),
"suspendAndUnitConversionInlineReified" to suspendAndUnitConversion(::inlineReifiedF),
"suspendAndDefaultConversionInlineReified" to suspendAndDefaultConversion(::inlineReifiedF),
"suspendAndVarargConversionInlineReified" to suspendAndVarargConversion(::inlineReifiedF),
"unitAndDefaultConversionInlineReified" to unitAndDefaultConversion(::inlineReifiedF),
"unitAndVarargConversionInlineReified" to unitAndVarargConversion(::inlineReifiedF),
"defaultAndVarargConversionInlineReified" to defaultAndVarargConversion(::inlineReifiedF),
"allExceptSuspendConversionInlineReified" to allExceptSuspendConversion(::inlineReifiedF),
"allExceptUnitConversionInlineReified" to allExceptUnitConversion(::inlineReifiedF),
"allExceptVarargConversionInlineReified" to allExceptVarargConversion(::inlineReifiedF),
"allExceptDefaultConversionInlineReified" to allExceptDefaultConversion(::inlineReifiedF),
"allConversionsInlineReified" to allConversions(::inlineReifiedF),
)
for ((name1, ref1) in allRefs) {
for ((name2, ref2) in allRefs) {
if (name1 != name2) {
if (ref1 == ref2) {
return "$name1 and $name2 wrappers should not be equal"
}
}
}
}
return "OK"
}
@@ -1,9 +1,19 @@
// !LANGUAGE: +SuspendConversion
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// FILE: suspendCovnersion.kt
fun checkNotEqual(x: Any, y: Any) {
if (x == y || y == x) throw AssertionError("$x and $y should NOT be equal")
}
fun checkEqual(x: Any, y: Any) {
if (x != y || y != x) throw AssertionError("$x and $y should be equal")
if (x.hashCode() != y.hashCode()) throw AssertionError("$x and $y should have the same hash code")
}
fun capturePlain(fn: () -> Unit): Any = fn
fun captureSuspend(fn: suspend () -> Unit): Any = fn
@@ -26,18 +36,30 @@ fun box(): String {
val c = C()
checkNotEqual(capturePlain(::foo), captureSuspend(::foo))
checkEqual(capturePlain(::foo), capturePlain(::foo))
checkEqual(captureSuspend(::foo), captureSuspend(::foo))
checkNotEqual(capturePlain(c::memberFun), captureSuspend(c::memberFun))
checkEqual(capturePlain(c::memberFun), capturePlain(c::memberFun))
checkEqual(captureSuspend(c::memberFun), captureSuspend(c::memberFun))
checkNotEqual(captureOther1(), captureOther2())
checkNotEqual(captureBoundOther1(c), captureBoundOther2(c))
checkNotEqual(capturePlainInt(::fnWithVararg), captureSuspendInt(::fnWithVararg))
checkNotEqual(captureSuspend(::fnWithVararg), captureSuspendInt(::fnWithVararg))
checkEqual(capturePlainInt(::fnWithVararg), capturePlainInt(::fnWithVararg))
checkEqual(captureSuspendInt(::fnWithVararg), captureSuspendInt(::fnWithVararg))
checkEqual(captureSuspend(::fnWithVararg), captureSuspend(::fnWithVararg))
checkNotEqual(capturePlainInt(::fnWithDefault), captureSuspendInt(::fnWithDefault))
checkNotEqual(captureSuspend(::fnWithDefault), captureSuspendInt(::fnWithDefault))
checkEqual(capturePlainInt(::fnWithDefault), capturePlainInt(::fnWithDefault))
checkEqual(captureSuspendInt(::fnWithDefault), captureSuspendInt(::fnWithDefault))
checkEqual(captureSuspend(::fnWithDefault), captureSuspend(::fnWithDefault))
checkNotEqual(capturePlain(::fnReturnsInt), captureSuspend(::fnReturnsInt))
checkEqual(capturePlain(::fnReturnsInt), capturePlain(::fnReturnsInt))
checkEqual(captureSuspend(::fnReturnsInt), captureSuspend(::fnReturnsInt))
return "OK"
}
@@ -2,8 +2,6 @@
// WASM_MUTE_REASON: FAILS_IN_JS_IR
// IGNORE_BACKEND: JS, JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// KT-55462
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -1,8 +1,6 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: IGNORED_IN_JS
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
// KT-55463
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -1,8 +1,6 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: IGNORED_IN_JS
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
// KT-55463
// IGNORE_BACKEND_K2: NATIVE
// FILE: test.kt
fun checkEqual(x: Any, y: Any) {
@@ -1,8 +1,6 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: IGNORED_IN_JS
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
// KT-55463
// IGNORE_BACKEND_K2: NATIVE
fun checkEqual(x: Any, y: Any) {
if (x != y || y != x) throw AssertionError("$x and $y should be equal")
@@ -3718,6 +3718,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -3826,6 +3826,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -3219,6 +3219,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Equality extends AbstractLightAnalysisModeTest {
@TestMetadata("conversionCombinations.kt")
public void ignoreConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -2524,6 +2524,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -2578,6 +2578,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -2578,6 +2578,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -2578,6 +2578,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -2292,6 +2292,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/extensionReceiverVsDefault.kt");
@@ -155,12 +155,17 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
break
}
if (!expression.type.isFunction() && !expression.type.isKFunction()
&& !expression.type.isKSuspendFunction()) {
if (!expression.type.isFunction() && !expression.type.isKFunction() &&
!expression.type.isKSuspendFunction() && !expression.type.isSuspendFunction()) {
// Not a subject of this lowering.
return expression
}
if (expression.origin.isLambda && expression.type.isSuspendFunction()) {
// Handled later by coroutines lowerings
return expression
}
return transformFunctionReference(expression)
}
@@ -203,12 +208,10 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private val isLambda = functionReference.origin.isLambda
private val isKFunction = functionReference.type.isKFunction()
private val isKSuspendFunction = functionReference.type.isKSuspendFunction()
private val adaptedReferenceOriginalTarget: IrFunction? = functionReference.reflectionTarget?.owner
private val functionReferenceTarget = adaptedReferenceOriginalTarget ?: referencedFunction
private val isK = functionReference.type.isKFunction() || functionReference.type.isKSuspendFunction()
private val isSuspend = functionReference.type.isSuspendFunction() || functionReference.type.isKSuspendFunction()
private val adaptedReferenceOriginalTarget = referencedFunction.getAdapteeFromAdaptedForReferenceFunction()
private val functionReferenceTarget = adaptedReferenceOriginalTarget ?:referencedFunction
/**
* The first element of a pair is a type parameter of [referencedFunction], the second element is its argument in
@@ -329,8 +332,8 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
)
}
val superClass = when {
isKSuspendFunction -> kSuspendFunctionImplSymbol.typeWith(functionReturnType)
isLambda -> irBuiltIns.anyType
isSuspend -> kSuspendFunctionImplSymbol.typeWith(functionReturnType)
else -> kFunctionImplSymbol.typeWith(functionReturnType)
}
val superTypes = mutableListOf(superClass)
@@ -342,12 +345,12 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
transformedSuperMethod = remappedSuperType.classOrNull!!.functions.single { it.owner.modality == Modality.ABSTRACT }.owner
} else {
val numberOfParameters = unboundFunctionParameters.size
if (isKSuspendFunction) {
val suspendFunctionClass = symbols.kSuspendFunctionN(numberOfParameters).owner
if (isSuspend) {
val suspendFunctionClass = (if (isK) symbols.kSuspendFunctionN(numberOfParameters) else symbols.suspendFunctionN(numberOfParameters)).owner
superTypes += suspendFunctionClass.typeWith(functionParameterAndReturnTypes)
transformedSuperMethod = suspendFunctionClass.invokeFun!!
} else {
val functionClass = (if (isKFunction) symbols.kFunctionN(numberOfParameters) else symbols.functionN(numberOfParameters)).owner
val functionClass = (if (isK) symbols.kFunctionN(numberOfParameters) else symbols.functionN(numberOfParameters)).owner
superTypes += functionClass.typeWith(functionParameterAndReturnTypes)
transformedSuperMethod = functionClass.invokeFun!!
}
@@ -437,7 +440,7 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
val superConstructor = when {
isKSuspendFunction -> kSuspendFunctionImplConstructorSymbol.owner
this@FunctionReferenceBuilder.isSuspend -> kSuspendFunctionImplConstructorSymbol.owner
isLambda -> irBuiltIns.anyClass.owner.constructors.single()
else -> kFunctionImplConstructorSymbol.owner
}
@@ -472,7 +475,7 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
listOfNotNull(
(1 shl 0).takeIf { referencedFunction.isSuspend },
(1 shl 1).takeIf { hasVarargMappedToElement() },
(1 shl 2).takeIf { adaptedReferenceOriginalTarget?.isSuspend == false && referencedFunction.isSuspend },
(1 shl 2).takeIf { isSuspendConversion() },
(1 shl 3).takeIf { isCoercedToUnit() },
(1 shl 4).takeIf { isFunInterfaceConstructorAdapter() }
).sum()
@@ -489,6 +492,9 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
private fun isCoercedToUnit() =
adaptedReferenceOriginalTarget?.returnType?.isUnit() == false && referencedFunction.returnType.isUnit()
private fun isSuspendConversion() =
adaptedReferenceOriginalTarget?.isSuspend == false && referencedFunction.isSuspend
private fun hasVarargMappedToElement(): Boolean {
if (adaptedReferenceOriginalTarget == null) return false
val originalParameters = adaptedReferenceOriginalTarget.allParameters
@@ -2673,6 +2673,12 @@ public class K2NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTes
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {
@@ -2640,6 +2640,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt");
}
@Test
@TestMetadata("conversionCombinations.kt")
public void testConversionCombinations() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt");
}
@Test
@TestMetadata("extensionReceiverVsDefault.kt")
public void testExtensionReceiverVsDefault() throws Exception {