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 c93a8a74826..72ab6c60546 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 @@ -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 { 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 8d75302ae6c..62227664272 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 @@ -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 diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 7a662f4528f..0a6a9e18f0d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/callableReference/equality/capturedDefaults.kt b/compiler/testData/codegen/box/callableReference/equality/capturedDefaults.kt index b713d4b27a7..a9f68a86f71 100644 --- a/compiler/testData/codegen/box/callableReference/equality/capturedDefaults.kt +++ b/compiler/testData/codegen/box/callableReference/equality/capturedDefaults.kt @@ -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) { diff --git a/compiler/testData/codegen/box/callableReference/equality/capturedVararg.kt b/compiler/testData/codegen/box/callableReference/equality/capturedVararg.kt index d718368e688..4524cc3c13c 100644 --- a/compiler/testData/codegen/box/callableReference/equality/capturedVararg.kt +++ b/compiler/testData/codegen/box/callableReference/equality/capturedVararg.kt @@ -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) { diff --git a/compiler/testData/codegen/box/callableReference/equality/coercionToUnit.kt b/compiler/testData/codegen/box/callableReference/equality/coercionToUnit.kt index 773dafc1727..ff7085d9aa3 100644 --- a/compiler/testData/codegen/box/callableReference/equality/coercionToUnit.kt +++ b/compiler/testData/codegen/box/callableReference/equality/coercionToUnit.kt @@ -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) { diff --git a/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithDefaults.kt b/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithDefaults.kt index 10f0b24b264..7704901247e 100644 --- a/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithDefaults.kt +++ b/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithDefaults.kt @@ -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) { diff --git a/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt b/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt index 3a1a38a10ee..6ea6b6a154e 100644 --- a/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt +++ b/compiler/testData/codegen/box/callableReference/equality/coercionToUnitWithVararg.kt @@ -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) { diff --git a/compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt b/compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt new file mode 100644 index 00000000000..70654dc221c --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/equality/conversionCombinations.kt @@ -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 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, Int) -> Int) = ref +fun suspendConversion(ref: suspend (Int, Array, Int) -> Int) = ref +fun unitConversion(ref: (Int, Array, Int) -> Unit) = ref +fun defaultConversion(ref: (Int, Array) -> Int) = ref +fun varargConversion(ref: (Int, String, Int) -> Int) = ref +fun suspendAndUnitConversion(ref: suspend (Int, Array, Int) -> Unit) = ref +fun suspendAndDefaultConversion(ref: suspend (Int, Array) -> Int) = ref +fun suspendAndVarargConversion(ref: suspend (Int, String, Int) -> Int) = ref +fun unitAndDefaultConversion(ref: (Int, Array) -> 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) -> 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/callableReference/equality/suspendConversion.kt b/compiler/testData/codegen/box/callableReference/equality/suspendConversion.kt index 0c521662b72..479b801d99a 100644 --- a/compiler/testData/codegen/box/callableReference/equality/suspendConversion.kt +++ b/compiler/testData/codegen/box/callableReference/equality/suspendConversion.kt @@ -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" } diff --git a/compiler/testData/codegen/box/callableReference/equality/varargWithDefaults.kt b/compiler/testData/codegen/box/callableReference/equality/varargWithDefaults.kt index 5b07396a118..7e333980366 100644 --- a/compiler/testData/codegen/box/callableReference/equality/varargWithDefaults.kt +++ b/compiler/testData/codegen/box/callableReference/equality/varargWithDefaults.kt @@ -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) { diff --git a/compiler/testData/codegen/box/funInterface/equality/functionReferencesBound.kt b/compiler/testData/codegen/box/funInterface/equality/functionReferencesBound.kt index 724cfcc1b0e..bf1a1bf05aa 100644 --- a/compiler/testData/codegen/box/funInterface/equality/functionReferencesBound.kt +++ b/compiler/testData/codegen/box/funInterface/equality/functionReferencesBound.kt @@ -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) { diff --git a/compiler/testData/codegen/box/funInterface/equality/functionReferencesUnbound.kt b/compiler/testData/codegen/box/funInterface/equality/functionReferencesUnbound.kt index d5594bf7429..75dad97425c 100644 --- a/compiler/testData/codegen/box/funInterface/equality/functionReferencesUnbound.kt +++ b/compiler/testData/codegen/box/funInterface/equality/functionReferencesUnbound.kt @@ -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) { diff --git a/compiler/testData/codegen/box/funInterface/equality/localFunctionReferences.kt b/compiler/testData/codegen/box/funInterface/equality/localFunctionReferences.kt index 95bb257dc93..a2c4ec0b172 100644 --- a/compiler/testData/codegen/box/funInterface/equality/localFunctionReferences.kt +++ b/compiler/testData/codegen/box/funInterface/equality/localFunctionReferences.kt @@ -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") 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 3bff0a8a5d1..545a5dd5526 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 @@ -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 { 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 f0f874ca29b..998c0c07681 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 @@ -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 { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 36249d6d8c9..c8db1d0281d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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); } 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 eccb44c2a07..1d666001aeb 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 @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java index f5d2238451b..78546d84d10 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java @@ -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 { 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 e339d1bb7f5..0b3540d8138 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 @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java index c82be9918c2..849f2955a97 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java @@ -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 { 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 8a93f356ad6..549321cb1d0 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 @@ -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"); diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt index 62bb9c543a1..701291db9dc 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.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 diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java index 68a4209d41e..baf25cb0b27 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java @@ -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 { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index db888676f2d..5e447212ac0 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -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 {