FIR translates:
```
when (x) {
1, 2, 3 -> action
else -> other_action
}
```
to an IR structure with nested ors:
```
if ((x == 1 || x == 2) || (x == 3)) action
else other_action
```
This change allows that to turn into switch instructions in the
JVM backend.
i.e. remove the condition that there must be an LVT entry. Such
temporary `Ref`s can be created, for example, by the JVM_IR backend
if a lambda inlined at an IR level (e.g. argument to `assert`/`Array`)
is the target of a non-local return from a function inlined at bytecode
level (e.g. `run`):
IntArray(n) { i ->
intOrNull?.let { return@IntArray it }
someInt
}
->
val `tmp$0` = IntArray(n)
for (i in 0 until `tmp$0`.size) {
var `tmp$1`: Int
do {
intOrNull?.let {
`tmp$1` = it // causes `tmp$1` to become an IntRef
break
}
`tmp$1` = someInt
} while (false)
`tmp$0`[i] = `tmp$1`
}
It's not correct to expect that the backend generates the `when` in this
test as tableswitch because there are only two branches. JVM IR has a
cutoff in the when optimization and generates `when`s with fewer than 3
branches as if-else chains, which is probably better. Note that there's
also a corresponding box test in when/enumOptimization/, so the backend
behavior is still tested.
This gives us more precise type information and can enable backend
optimizations. This was motivated by when expressions not compiled
to table switches in the JVM_IR backend.
Fixed KT-36845.
When synthesizing the hashCode function for data classes, descriptors
were used, in partcular, memberScope for primitive classes.
IrBasedDescriptors have no member scope, so we compute the hashCode
function based on IR structures.
The existing backend restores LVs and parameters from the suspend lambda
fields used for spilling between suspension points, hence they are
visible in the debugger as local variables, plain and simple.
This PR introduces the same pattern to the IR backend, to bring the
debugging experience in line with the existing backend.
Both backends are still at the mercy of the liveness analysis
performed in the coroutine transformer where a liveness analysis
minimizes live ranges of entries in the LVT. E.g. an unused parameter
will be dropped entirely.
Adjusted existing test expectations accounting for the differences in
LV behavior.
The current backend uses direct field access to the backing field
instead of calling the companion object accessor, which calls
an accessibility bridge, which then gets the field for code such as:
```
class A {
companion object {
val s: String = "OK"
}
// f uses direct access to the A.s backing field.
fun f() = s
}
```
This change does the same for the IR backend.
'allopen' compiler plug-in can make data classes and their members open,
which is a compilation error in usual case, but makes sense for Spring
and other frameworks that generate proxy-classes.
Before this commit, questionable optimization existed which
unwrapped string interpolating call with single argument to this argument.
However, this led to source element loss and the necessity of sub-hacks.
In this commit we dropped this optimization (anyway user can remove
this single-expression string template in code if needed) to keep
source elements intact.
1. Use 'x' for each parameter, which is not an inline class, every
possible clash is handled by signature rather than name. This change
makes more API changes binary-compatible. So, the changes are in line
with the vision of inline classes are value classes, like primitives.
2. Take return type into account when mangling a function if the return
type is inline class. Otherwise, boxing bridge will not be generated,
which leads to CCE at runtime.