1cb1420e43
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
54 lines
1.1 KiB
Kotlin
Vendored
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}"
|
|
}
|