Consider a context with uninitialized this, e.g.:
fun foo() {
val x = "..."
class Local(y: String) : Base(L@{ x + y })
}
Lambda 'L' is an argument of a super class constructor call.
Here 'this@Local' is not initialized yet. Thus local variables captured
in 'Local' can't be used. Instead, they should be captured by lambda 'L'
itself.
Note that lambda 'L' sees both 'x' and 'y' as local variables that
should be captured.
When in context with uninitialized this (generating arguments for super
type constructor or delegating constructor call), and a variable in
question is not found in the current context, use enclosing local lookup
to determine whether a local variable should be captured by a closure.
Enclosing class for closure is a class whose instance is captured by
closure as an outer 'this', and stored in a field 'this$0'.
Usually enclosing class for closure is an immediate outer class,
including classes for nested closures. For example:
class C {
fun foo() {}
val example1 = L1@ { foo() }
// Enclosing class for lambda 'L1' is 'C'
val example2 = L2a@ { L2b@ { foo() } }
// Enclosing class for nested lambda 'L2b'
// is a closure class for outer lambda 'L2a'
}
However, if the closure is created in a super type constructor call for
the outer class, corresponding instance is considered "uninitialized",
and can't be used as a proper class instance, and can't be referenced:
corresponding code is rejected by front-end.
class Outer {
fun foo() {}
inner class Inner : Base(L3@ { foo() })
// Enclosing class for lambda 'L3' is 'Outer',
// because 'Inner' is uninitialized in super type constructor call.
}
In CodegenAnnotatingVisitor, we maintain a stack of currently
uninitialized classes, and chose enclosing class for closure
as an inner-most surrounding class with initialized instance.
When generating code for this or outer class instance, we skip
contexts corresponding to classes with uninitialized instances.
This fixes a number of bytecode verification errors caused by incorrect
enclosing class for closure.
#KT-4174 Fixed Target versions 1.2.20
#KT-13454 Fixed Target versions 1.2.20
#KT-14148 Fixed Target versions 1.2.20
Codegen generates clean instructions for ref values (captured vars)
on block exit so we should delete them on dereferencing captured values.
#KT-17200 FIXED
This patch mutes the following test categories:
* Tests with java dependencies (System class,
java stdlib, jvm-oriented annotations etc).
* Coroutines tests.
* Reflection tests.
* Tests with an inheritance from the standard
collections.
There are mainly two kind of changes:
- skipping 'componentX' calls for destructuring entries named _
- fixing local variable table for them
- skip entries for destructuring entries named _
- use $noName_<i> format for lambda parameters named _
#KT-3824 Fixed
#KT-2783 Fixed
There is a lot of changes about closures calculating and generating.
1. As classes can have more than one constructor each of them should
have closure arguments.
2. Captured variables set is the same for all of them.
3. Within constructors bodies/delegating calls closure parameters
should be accessed through method arguments because fields may be
not initialized yet.
When property initializer of some inner entity (e.g. anonymous object) contains
a reference to some outer entity (say, a property of the outer class), we need
to make sure we called "lookupInContext" on this entity's owner class, so that
"setCaptureThis" was called on the appropriate closure
#KT-4176 Fixed
KT-4106: VerifyError: Can't access outer this in a lambda in inner class' constructor
KT-3152: VerifyError when accessing from a function of object to a field of outer outer class
#KT-3523 Fixed
#KT-4106 Fixed
#KT-3152 Fixed
Superclass of closures should now be FunctionImplN instead of FunctionN. Since
these -Impl classes are needed only in JVM, the corresponding descriptors and
types are created in the back-end only.