Move lateinit assertion for companion property to companion object

Previously, for a property named `x` in the companion object of a class
named `Foo`, we generated:
- `Foo.access$getX$cp`, consisting of `GETFIELD Foo.x` and lateinit
  assertion
- `Foo.Companion.getX`, consisting of `INVOKEVIRTUAL Foo.access$getX$cp`

Now, we generate:
- `Foo.access$getX$cp`, consisting of `GETFIELD Foo.x`
- `Foo.Companion.getX`, consisting of `INVOKEVIRTUAL Foo.access$getX$cp`
  and lateinit assertion

The reason is that this way we can avoid generating another accessor and
reuse `Foo.access$getX$cp` in case `isInitialized` is called on a
lateinit property from companion.

For private properties, getX is not generated, but instead the assertion
is generated on each access to the field (which can be improved, see
KT-28331). The same happens for access to non-private properties from
inside the same context where they're declared.

 #KT-21862 In Progress
This commit is contained in:
Alexander Udalov
2018-11-19 18:13:29 +01:00
parent 8617365983
commit 43413fcc44
11 changed files with 185 additions and 16 deletions
@@ -1,21 +1,32 @@
public class A {
fun getMyStr(): String {
fun getFromClass(): Boolean {
try {
val a = str
return false
} catch (e: RuntimeException) {
return "OK"
return true
}
return "FAIL"
}
fun getFromCompanion() = Companion.getFromCompanion()
private companion object {
private lateinit var str: String
fun getFromCompanion(): Boolean {
try {
val a = str
return false
} catch (e: RuntimeException) {
return true
}
}
}
}
fun box(): String {
val a = A()
return a.getMyStr()
}
if (!A().getFromClass()) return "Fail getFromClass"
if (!A().getFromCompanion()) return "Fail getFromCompanion"
return "OK"
}
@@ -0,0 +1,40 @@
public class A {
fun getFromClass(): Boolean {
try {
val a = str
return false
} catch (e: RuntimeException) {
return true
}
}
fun getFromLambda(): Boolean {
try {
val a = { str }()
return false
} catch (e: RuntimeException) {
return true
}
}
companion object {
lateinit var str: String
fun getFromCompanion(): Boolean {
try {
val a = str
return false
} catch (e: RuntimeException) {
return true
}
}
}
}
fun box(): String {
if (!A().getFromClass()) return "Fail getFromClass"
if (!A().getFromLambda()) return "Fail getFromLambda"
if (!A.getFromCompanion()) return "Fail getFromCompanion"
return "OK"
}
@@ -0,0 +1,24 @@
class Foo {
private companion object {
lateinit var x: String
fun test() {
consume(x)
consume(x)
consume(x)
consume(x)
}
}
fun test2() {
consume(x)
consume(x)
consume(x)
consume(x)
}
}
fun consume(s: String) {}
// There's 1 assertion in Foo.Companion.getX, and 4 in Foo.test2 (see KT-28331)
// 5 throwUninitializedPropertyAccessException
@@ -0,0 +1,20 @@
class Foo {
private companion object {
lateinit var x: String
fun test() {
consume({ x }());
{ consume(x) }()
}
}
fun test2() {
consume({ x }());
{ consume(x) }()
}
}
fun consume(s: String) {}
// There's only one assertion in Foo.Companion.getX
// 1 throwUninitializedPropertyAccessException