While within a method by the JVM spec null-value has a special
Nothing-like type, when we spill it for a coroutine, we must choose
some real type to CHECKCAST to after restoring the variable's value.
But the problem is that such a real type depends on usage of that null value,
and there may be more than one usage.
The solution is not to spill such variables into fields, but instead
init them with ACONST_NULL after each suspension point
#KT-16122 Fixed
The main problem is that inside a state machine for a named suspend
function parameters of it's owner are available as a usual captured
closure parameters (i.e. through synthetic fields), while
TailRecursion codegen expects that parameters are straight local
variables.
So, the solution is just to define local var for each of real parameters
(all but the last continuation parameters) for tailrec functions.
#KT-15759 Fixed
The problem was that we spilled the `origin` variable (see test) as Object, because
we determined the type of merge(null, String) incorrectly.
#KT-15973 Fixed
Suspend function call with a reachable (alive) begin marker and unreachable (dead) end marker
is an exit point for the corresponding coroutine.
It isn't a suspension point, and doesn't introduce a new state in the coroutine FSM.
- Determine if there are non-tail calls to getValue/setValue simply
by existance of such a property
(it might be too strict, but implementing more granular check may be rather hard)
- Change in ExpressionCodegen is relevant for provideDelegate,
that in case of local variables uses OnStack as StackValue
(see the comment near these changes)
#KT-15933 Fixed
1. JVM view of suspend accessors must be also an instance of AccessorForFunctionDescriptor,
thus `createSubstitutedCopy` should be correctly overidden.
2. accessibleFunctionDescriptor should unwap the initial suspend descriptor,
for the same reasons as for type aliases constructors and etc:
these descriptors are used as keys of the map of accessors, so
to avoid duplication for suspend view and initial suspend descriptor,
we always use the latter one as a key.
#KT-15907 Fixed
#KT-15935 Fixed
When the extension receiver of a named suspend function was marked as used
from the inner lambda, codegen used to throw a "Don't know how to generate outer expression for class" exception.
It may seem quite tricky, but currently for suspend lambda body
its extension receiver is treated as it's defined inside the relevant "doResume"
(there is an actual bytecode part that fills the relevant local variable)
The problem was that inside ExpressionCodegen for "doResume" of named
suspend function we couldn't determine that original function has
an extension receiver.
#KT-15821 Fixed
#KT-15820 Fixed
If all the suspension calls in a suspend function were "hidden"
under the for-convention (iterator/next/hasNext) calls,
control-flow didn't find them, thus supposing that there is no
suspension points and there is no need to generate a coroutine state machine
The solution is to add relevant calls to CFG
#KT-15824 Fixed
The problem is that code in the attached test led to VerifyError at runtime
because the Bar's uninitialized instance created in 'map' was being stored
to the field (leaked from the JVM point of view).
The actual problem was that after repeating visiting of NEW operation
we used to drop the set of already visited copy usages.
For clarification see the comment before 'processUninitializedStores'
#KT-15016 Fixed
ContinuationInterceptor companion object is named Key
CoroutineContext.Element property for key is named just key
AbstractCoroutineContextElement implements all of CoroutineContext.Element, including key
The problem appears for tail-optimized suspend functions,
we erroneously assumed that when/if/try expressions in tail-call
position have simple types like `I` while actually, they can return SUSPENDED
object, i.e. must have `java/lang/Object` as return type.
But this only concerns branching operations in tail-call position,
so we have to make an additional analysis for remembering whether
a given expression is in a tail-call position.
Also, it's important here that we now assume
the return type of the current function as `java/lang/Object`
that is necessary to avoid wrong checkcasts.
#KT-15364 Fixed
Not all the `hasNext` operators return types is exactly Z,
suspend operators return boxed versions.
So the fix is just coercing result value after invoked function to Z
This change should make the logic a bit more simple.
For all suspend functions/coroutines treat them in expression codegen
like they return boxed version of the original type.
Everything works fine then, except Unit type functions:
their bodies must be generated just like they're VOID and then load
Unit on stack manually.