Files
kotlin-fork/compiler/testData/codegen/box/polymorphicSignature/insideComplexExpression.kt
T
Alexander Udalov 1cb1420e43 JVM: push down implicit coercion to Unit in IR
This is basically a workaround for a slightly different IR generated by
fir2ir vs psi2ir. Simplified, psi2ir generates something like this for
the sample from KT-59218:

  TRY type=Unit
    try: BLOCK type=Unit
      VAR methodHandle [...]
      TYPE_OP type=Unit origin=IMPLICIT_COERCION_TO_UNIT
        CALL invokeExact [...]

While fir2ir generates the following:

  TYPE_OP type=Unit origin=IMPLICIT_COERCION_TO_UNIT
    TRY type=Any?
      try: BLOCK type=Any?
        VAR methodHandle [...]
        CALL invokeExact [...]

The lowering relies on the fact that a polymorphic call (`invokeExact`
in this case) is a direct argument to the TYPE_OP, to determine the
correct return type (Unit in this case) to be generated in the bytecode.

The solution here is to push the type coercion "through" all the
block-like structures (`try`, `when`, container expression) so that if
the last statement in the block is a polymorphic call, it gets properly
converted even if the whole block is under a type coercion operation, as
it happens in fir2ir. We achieve that by using the "data" parameter of
the IR transformer: appropriate immediate children of
IrTypeOperatorCall/IrTry/IrWhen/IrContainerExpression get the type that
the expression needs to be coerced to, and all the other expressions
ignore that type and set it to null when transforming their children.

A proper solution would be to ensure fir2ir generates exactly the same
IR as psi2ir (KT-59781), but since PolymorphicSignatureLowering is the
only lowering affected so far, and polymorphic calls occur very rarely,
it seems safe to workaround it in the lowering for now.

 #KT-59218 Fixed
2023-07-18 11:37:42 +00:00

54 lines
1.1 KiB
Kotlin
Vendored

// TARGET_BACKEND: JVM
// WITH_STDLIB
// FULL_JDK
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
object Counter {
var result = 0
var exception = false
fun inc() {
result++
if (exception) throw AssertionError()
}
}
val mh = MethodHandles.lookup().findVirtual(Counter::class.java, "inc", MethodType.methodType(Void.TYPE))
fun f(x: Int) {
when (x) {
1 -> try {
throw Exception()
} catch (e: Exception) {
if (x > 42) {} else mh.invokeExact(Counter)
}
2 -> if (x < 42) {
if (x < 4242) mh.invokeExact(Counter) else {}
}
3 -> try {
try {
mh.invokeExact(Counter)
} finally {
mh.invokeExact(Counter)
}
} catch (e: AssertionError) {
Counter.exception = false
mh.invokeExact(Counter)
} finally {
mh.invokeExact(Counter)
}
}
}
fun box(): String {
f(1)
f(2)
Counter.exception = true
f(3)
return if (Counter.result == 6) "OK" else "Fail: ${Counter.result}"
}