Local declarations and initializers fixes (#222)
* captured values are stored in corresponding fields before call to super constructor * preserving the order of initializers * tests * refactoring * - test fix - workaround of IR bug * refactoring * review fix
This commit is contained in:
+9
@@ -3,7 +3,9 @@ package org.jetbrains.kotlin.backend.common.lower
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -82,6 +84,13 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
closuresStack.peek()?.addNested(closure)
|
||||
}
|
||||
|
||||
// TODO: remove as soon as bug in IrSetterCallImpl is fixed.
|
||||
override fun visitCall(expression: IrCall) {
|
||||
super.visitCall(expression)
|
||||
if (expression is IrSetterCallImpl)
|
||||
visitElement(expression.getValueArgument(0)!!)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
val functionDescriptor = declaration.descriptor
|
||||
val closureBuilder = FunctionClosureBuilder(functionDescriptor)
|
||||
|
||||
+24
-11
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
@@ -327,6 +328,9 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
||||
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE") {}
|
||||
|
||||
private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE :
|
||||
IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE") {}
|
||||
|
||||
private fun rewriteClassMembers(irClass: IrClass, localClassContext: LocalClassContext) {
|
||||
irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext))
|
||||
|
||||
@@ -334,23 +338,25 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
TODO("local classes without primary constructor")
|
||||
|
||||
val primaryConstructorContext = localClassConstructors[primaryConstructor]!!
|
||||
val primaryConstructorBody = primaryConstructorContext.declaration.body as? IrBlockBody
|
||||
?: throw AssertionError("Unexpected constructor body: ${primaryConstructorContext.declaration.body}")
|
||||
|
||||
localClassContext.capturedValueToField.forEach { capturedValue, fieldDescriptor ->
|
||||
|
||||
val capturedValueExpression =
|
||||
primaryConstructorContext.irGet(irClass.startOffset, irClass.endOffset, capturedValue)!!
|
||||
|
||||
val startOffset = irClass.startOffset
|
||||
val endOffset = irClass.endOffset
|
||||
irClass.declarations.add(
|
||||
IrFieldImpl(
|
||||
irClass.startOffset, irClass.endOffset,
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
|
||||
fieldDescriptor,
|
||||
IrExpressionBodyImpl(
|
||||
irClass.startOffset, irClass.endOffset,
|
||||
capturedValueExpression
|
||||
)
|
||||
fieldDescriptor
|
||||
)
|
||||
)
|
||||
|
||||
val capturedValueExpression = primaryConstructorContext.irGet(startOffset, endOffset, capturedValue)!!
|
||||
val capturedValueInitializer = IrSetFieldImpl(startOffset, endOffset, fieldDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter),
|
||||
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE)
|
||||
primaryConstructorBody.statements.add(0, capturedValueInitializer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,7 +601,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
private fun suggestNameForCapturedValue(valueDescriptor: ValueDescriptor): Name =
|
||||
if (valueDescriptor.name.isSpecial) {
|
||||
val oldNameStr = valueDescriptor.name.asString()
|
||||
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
|
||||
oldNameStr.substring(1, oldNameStr.length - 1).synthesizedName
|
||||
} else
|
||||
valueDescriptor.name
|
||||
|
||||
@@ -639,6 +645,13 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
// TODO: remove as soon as bug in IrSetterCallImpl is fixed.
|
||||
override fun visitCall(expression: IrCall) {
|
||||
super.visitCall(expression)
|
||||
if (expression is IrSetterCallImpl)
|
||||
visitElement(expression.getValueArgument(0)!!)
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.declaredInFunction() = when (this.containingDeclaration) {
|
||||
is CallableDescriptor -> true
|
||||
is ClassDescriptor -> false
|
||||
|
||||
+12
-9
@@ -22,7 +22,6 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
|
||||
private inner class InitializersTransformer(val irClass: IrClass) {
|
||||
val fieldInitializers = mutableListOf<IrStatement>()
|
||||
val initializers = mutableListOf<IrStatement>()
|
||||
|
||||
fun lowerInitializers() {
|
||||
@@ -34,34 +33,38 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
||||
IrStatementOriginImpl("ANONYMOUS_INITIALIZER")
|
||||
|
||||
private fun collectAndRemoveInitializers() {
|
||||
// Do with one traversal in order to preserve initializers order.
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
// Skip nested.
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
|
||||
initializers.add(IrBlockImpl(declaration.startOffset, declaration.endOffset,
|
||||
context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, declaration.body.statements))
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField): IrStatement {
|
||||
val initializer = declaration.initializer ?: return declaration
|
||||
val propertyDescriptor = declaration.descriptor
|
||||
val startOffset = initializer.startOffset
|
||||
val endOffset = initializer.endOffset
|
||||
fieldInitializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
|
||||
initializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
|
||||
listOf(
|
||||
IrSetFieldImpl(startOffset, endOffset, propertyDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter),
|
||||
initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
|
||||
return IrFieldImpl(declaration.startOffset, declaration.endOffset, declaration.origin, propertyDescriptor)
|
||||
declaration.initializer = null
|
||||
return declaration
|
||||
}
|
||||
})
|
||||
|
||||
irClass.declarations.transformFlat {
|
||||
if (it !is IrAnonymousInitializer)
|
||||
null
|
||||
else {
|
||||
initializers.add(IrBlockImpl(it.startOffset, it.endOffset,
|
||||
context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, it.body.statements))
|
||||
listOf()
|
||||
}
|
||||
else listOf()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +80,7 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
||||
|
||||
blockBody.statements.transformFlat {
|
||||
when {
|
||||
it is IrInstanceInitializerCall -> fieldInitializers + initializers
|
||||
it is IrInstanceInitializerCall -> initializers
|
||||
/**
|
||||
* IR for kotlin.Any is:
|
||||
* BLOCK_BODY
|
||||
|
||||
@@ -404,6 +404,21 @@ task localClass_innerTakesCapturedFromOuter(type: RunKonanTest) {
|
||||
source = "codegen/localClass/innerTakesCapturedFromOuter.kt"
|
||||
}
|
||||
|
||||
task localClass_virtualCallFromConstructor(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/virtualCallFromConstructor.kt"
|
||||
}
|
||||
|
||||
task initializers_correctOrder1(type: RunKonanTest) {
|
||||
goldValue = "42\n"
|
||||
source = "codegen/initializers/correctOrder1.kt"
|
||||
}
|
||||
|
||||
task initializers_correctOrder2(type: RunKonanTest) {
|
||||
goldValue = "42\n"
|
||||
source = "codegen/initializers/correctOrder2.kt"
|
||||
}
|
||||
|
||||
task array0(type: RunKonanTest) {
|
||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||
source = "runtime/collections/array0.kt"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
class Test {
|
||||
val x: Int
|
||||
|
||||
init {
|
||||
x = 42
|
||||
}
|
||||
|
||||
val y = x
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Test().y)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class Test {
|
||||
val x: Int
|
||||
|
||||
val y = 42
|
||||
|
||||
init {
|
||||
x = y
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Test().x)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
abstract class WaitFor {
|
||||
init {
|
||||
condition()
|
||||
}
|
||||
|
||||
abstract fun condition(): Boolean;
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val local = ""
|
||||
var result = "fail"
|
||||
val s = object : WaitFor() {
|
||||
|
||||
override fun condition(): Boolean {
|
||||
result = "OK"
|
||||
return result.length == 2
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -6,10 +6,6 @@ fun foo() : String {
|
||||
return u()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return foo()
|
||||
}
|
||||
Reference in New Issue
Block a user