I opt to identify any syntactic initializer. These are broader in scope than Java's member initializers, which are necessarily context-free, whereas in Kotlin the primary constructor's parameters can be referred to.
Pros:
* <obinit> no longer emitted: one less function per class
* Parameters to the primary constructor, if any, are no longer referred to out of scope
* Simple primary constructor `val` and `var` declarations work as expected
Cons:
* If there are multiple secondary constructors, no primary constructor and long init blocks, there could be considerable duplicate extraction of those init blocks. Hopefully this case is very rare.
These are extracted as "throw new kotlin.NoWhenBranchFoundException();", which is the Java lowering of the intrinsic.
In the process, amend the control-flow graph to let when branches propagate `throw`s outwards, and similarly statement expressions.
* Extract varargs as if they are ordinary positional arguments
* Adapt the QL that distinguishes varargs from ordinary arguments to account for Kotlin's varargs which can occur in the middle of the arg list
* Add a test checking dataflow through varargs which doesn't work yet due to array-get and array-set not being extracted as IndexExprs
* Extract the special case arrayOf(*x) as a clone call, which is (equivalent to) the Java lowering of that operation
Turns out type aliases are always substituted by the compiler, with the `IrSimpleType.abbreviation` field indicating what the original alias was if any. Therefore we're already extracting the right types. This commit simply omits extracting a kt_type for a type alias that uses type parameters as this certainly won't work at present because we don't have IrTypes for the type parameters declared by the alias and used in its RHS.
- Create a new operator representing an infix value [in]equality test, equivalent to Objects.equals(lhs, rhs)
- Continue to use simple equality where it is clearly possible at the callsite
- Note that ieee754equals is the same as Java's == and != operators
If it is used by the compiler to implement the infix plus operator, resugar it and extract a `+` as Java would. If it is literally called by the user (e.g. `(if (x) then "not null" else null).plus(something)`), then extract a call to the real method Intrinsics.stringPlus (a two-arg static method).