even when arguments are to be rearranged.
Lambdas have no side effects, and storing them in temporary variables
prevents processing in the backend
(such as inserting continuation parameter in AddContinuationLowering).
- Since neither IrProperty nor IrField is Type Parameter container
using of proprty's type parameter in IrField related code leads to
creation of "hanging" type parameters which should be considered as
incorrect IR.
- Such code designed to be prohibited in LV 1.5
- The fix makes use of erased type in such case
where type parameter is expected.
This seems to be the only reasonable way to provide function declarations with
_correctly_ substituted type parameters without rewriting logic from scratch;
correctly scoped type parameters in IR are now required in serialization
plugin by all backends.
Also fix some missing upper bounds.
Use resulting descriptor extension receiver type instead of
ReceiverValue.type (which can contain captured types, which would be
approximated, and cause IR validation errors).
Now SymbolTable operates with two types of symbols (public and private)
In case of Public symbol IdSignature is used as table key
Private one uses descriptor as the key in similar scheme as before
Previously, resolved call is expected to have SAM converted argument map
if SamConversionPerArgument is enabled. However, if SAM argument is
followed by vararg parameter and an array _without_ a spread operator is
passed, New Inference left a type mismatch error on a resolved call, which
made that resolved candidate filtered out. Instead, another resolution
result wihtout SAM converted arugment map will be provided.
All other logics, such as adding SAM conversion type op and lowering SAM
conversion and/or call references, are already there for resolved calls
without SAM converted argument map. This change just relaxes the bailout
condition so that array passed to vararg after SAM argument can be
handled in JVM IR.
Also:
* Do not rename public ABI fields
This includes backing fields for const, lateinit, @JvmField properties,
and instance fields for objects.
* FAKE_OVERRIDE declarations for static members of parent Java classes
Required to report cases when a Kotlin function accidentally overrides
Java class member.
All mutable state for IR declarations should be either:
- var (mutable properties)
- or class member list
Mutable properties are straightforward to persist.
The class member list is handled in a special way.
Don't insert implicit null check on a value of @EnhancedNullability type
used where @EnhancedNullability type is expected.
This uncovers a bunch of other problems in FE and BE.
KT-36343 and KT-36347 are bugs in StrictJavaNullabilityAssertions
implementation which should most likely be fixed in next major language
version (with proper breaking change notice).
KT-36344 is a design problem which should be addressed after 1.4 issues
are resolved.
Final default properties accessors that access a backing field
on the same class can be replaced by direct field use.
Perform the optimization late in the pipeline to allow lowerings
to expose more opportunities for optimizations.
When a property backed by a final field is the delegate for interface
implementation by delegation, the backend should reuse the backing
field rather than introduce a new, extraneous `$$delegate_n` field.
Final default properties accessors that access a backing field
on the same class can be replaced by direct field use.
Perform the optimization late in the pipeline to allow lowerings
to expose more opportunities for optimizations.
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
The main idea is the following: since we need to generate
(fake)continuations before inlining, we move IrClasses of suspend
lambdas and continuation classes of named functions into the functions.
Thus, it allows the codegen to generate them prior to inlining and
the inliner will happily transform them for us.
Because of that, lowerings which transform call-site function are likely
to change reference to lowered suspend lambdas or functions.
Hence, do not rely on references to lowered suspend lambdas or
functions, instead, rely on attributes.
Do not generate continuation for inline suspend lambdas.
Previously, inline suspend lambdas were treated like suspend functions,
thus we generated continuations for them. Now we just do not treat them
as suspend functions or lambdas during AddContinuationLowering.
We should add continuation parameter to them, however.
Do not generate secondary constructor for suspend lambdas, otherwise,
the inliner is unable to transform them (it requires only one
constructor to be present).
Generate continuation classes for suspend functions as first statement
inside the function.
This enables suspend functions in local object inside inline functions.
Since we already have attributes inside suspend named functions, we
just reuse them to generate continuation class names. This allows us
to close the gap between code generated by old back-end and the new
one.
If a suspend named function captures crossinline lambda, we should
generate a template for inliner: a copy of the function without
state-machine and a continuation constructor call. The call is needed
so the inliner transforms the continuation as well.
Refactor CoroutineTransformerMethodVisitor, so it no longer depends on
PSI.
This is a prerequisite to moving continuation classes inside said
functions, which is needed to support crossinline suspend lambdas.
The logic of whether to copy attributes on lowerings or not is simple:
- if the lowering moves function body to a new place, it should copy
the attributes.
- if the lowering just generates new declarations (i.e. bridges), it
should leave attributes as is.
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.