Callable reference is "adapted" if it requires some adaptation to an
expected function type - e.g., when a reference to
```
fun foo(vararg xs: Int): Int
```
is used where `(Int, Int, Int) -> Int` is expected.
For such callable references we generate the following IR (in
pseudo-Kotlin):
```
{
fun foo'(p0: Int, p1: Int, p2: Int): Int {
return [| foo(p0, p1, p2) |]
}
::foo'
}
```
where `[| foo(p0, p1, p2) |]` is calling function `foo` with arguments
`p0`, `p1`, and `p2`, as they were mapped by callable reference
resolution.
See KT-35849.
1. When expected lambda return type is a type parameter, don't generate
introduce implicit casts (even if the corresponding type parameter has
an upper bound that would otherwise require such cast).
2. Do not generate implicit null check for lambda return value of
@EnhancedNullability type.
It uses the same logic as an old back-end
(see SamType#createByValueParameter and genericSamProjectedOut.kt),
split into two parts:
1. When inserting SAM casts, use SamType#createByValueParamerer to get
the target SAM type.
2. When inserting implicit casts, cast SAM conversions as arguments of
methods of out-projected types to the original type of value parameter
instead of 'Nothing'.
Consider the following example:
Java:
public class J {
public static String foo() { return null; }
}
Kotlin:
fun check(fn: () -> Any) = fn()
fun test() = check { J.foo() }
When a lambda expression returns a value of platform type ('String!'),
corresponding lambda has platform type in its return type, which is
approximated to corresponding nullable type ('String?') in IR.
However, the lambda itself could occur in position with a functional
expected type ('() -> Any'). This implies an extra implicit cast on a
return value of lambda expression ('J.foo()'), although it conforms to
the return type of lambda.
When generating bodies for members implemented by delegation, invoke
corresponding delegate member, not an interface member. Otherwise we
might lose platform-specific nullability information in case of mixed
Kotlin-Java hierarchies, as in
implicitNotNullOnDelegatedImplementation.kt
NB here we have use derived class type with type arguments replaced
with star-projections. This emulates JVM erasure (to some degree),
but, unfortunately, that's best we can offer here at the moment.
Since property accessor descriptors (unlike corresponding IR elements)
do not have type parameters, we need to take them from the corresponding
property to ensure the correct IR for delegated property accessors.
We should only insert a return statement at the end of a lambda or
function if the final statement is used as an expression (slice
USED_AS_RESULT_OF_LAMBDA and USED_AS_EXPRESSION).
Rely on the frontend weeding out cases that are not supported.
In psi2ir, introduce all the parameters before processing default
values.
Change the DefaultArgumentStubGenerator to generate code that
matches the behavior of the current backend.
Preserve type substitution:
- when obtaining function type for SAM type;
- when generating SAM conversions for SAM adapter arguments;
- for "original" method corresponding to a SAM adapter.
Incorporate PR from Steven Schäfer into IrType-based implicit cast
insertion (commit 17b925636e8717e7648c5d7b792c6ab4d18f776d).
NB this still uses originalKotlinType to determine if the type was
nullability flexible. It is somewhat error-prone and something we want
to get rid of. However, it boils down to some design questions related
to implicit null checks in Kotlin - e.g., it might be Ok to just treat
nullability flexible type `T!` as `T?` in IR, generate null checks for
all usages of type `T?` where a non-null type is expected, and later
eliminate the null checks that are redundant according to the (quite
conservative) criterion in the redundant null check elimination.
Ideally, the type of `IrWhen` should be provided by type inference for
a consistent behavior. `USED_AS_EXPRESSION` from CFG isn't always
consistent with type inference, unfortunately.
The behavior is now aligned with `if`. The type of `when` is kept when
it *can* be an expression, instead of whether it is used or not.
Java constructors can have type parameters of their own:
public class J<X extends Number> {
public <Y extends CharSequence> J() {}
}
When such constructors are called from Kotlin, type parameters for
constructor follow type parameters for class:
fun test() = J<Int, String>() // <X=Int, Y=String>
Descriptor-based representation uses the same type parameters ordering.
Also, use 'withScope' in IrLazyFunction type parameters creation.
Augmented assignment operator (e.g., '+=') can be resolved to simple
function call ('plusAssign'). In that case, augmented assignment LHS
can be an arbitrary expression, and may have no associated ResolvedCall.
For example:
(a as MutableList<Int>) += 42
Note that it can happen only in case of augmented assignment operator
convention resolution, because all other forms of assignment-like
operator desugaring require some kind of 'store' operation
(property setter, 'set' operator for array element expression, etc),
and should resolve to some combination of calls.
In that case we simply generate LHS on 'load', and throw assertion on
'store'.
* if enum class has abstract members, then it is ABSTRACT
* otherwise, if enum class has entries with members, then it is OPEN
* otherwise, it is FINAL.
In super class constructor arguments, 'this' can be resolved
as a reference to a companion object of a superclass.
This breaks an assumption in psi2ir that 'this' can only refer to some
receiver from the current scope.
If 'this' refers to an 'object' (including 'companion obejct'),
and we are not inside the corresponding class scope,
then 'this' represents a reference to a singleton instance "by name"
(represented as IrGetObjectValue).
In the desugaring for compound assignment to a collection element,
argument expression 'i' is mapped to value parameters 'iG' and 'iS' of
corresponding 'get' and 'set' operators.
In general, these value parameters can have different indices.
This requires extra machinery in argument generation - that is, to be
able to generate a particular expression argument using an arbitrary
callback. In the vast majority of the cases this callback will just use
the corresponding StatementGenerator to generate IR subtree for the
provided expression. In case of 'get' and 'set' operator calls for an
augmented assignment expression this will map corresponding argument
expressions to pregenerated temporary variables.
Thus, in the following context:
```
class A
operator fun A.get(vararg xs: Int) = 0
operator fun A.set(i: Int, j: Int, v: Int) {}
```
statement `a[1, 2] += 3` will be desugared as (in a really pseudo
Kotlin):
```
{
val tmp_array = a
val tmp_index0 = 1
val tmp_index1 = 2
tmp_array.set(
i = tmp_index0,
j = tmp_index1,
v = tmp_array.get(xs = [tmp_index0, tmp_index1]).plus(3)
)
}
```