Initializers lowering fix: clone init blocks. (#321)

* Initializers lowering fix: clone init blocks.

In order to let following phases to modify IR we need to clone init blocks
for each constructor before inserting it.

* Used DeepCopyIRTreeWithDescriptors.

* Shared variables lowering must be performed before local functions lowering.

Local functions lowering makes all variables non-shared, thus they must be
transformed into Ref<> before this.

* Moved all initializers into a method.

In order not to deal with copying of IR at all it is easier to create a
method 'initialize' which will be called from each constructor.

* Used right parameters for call.

* If class has primary constructor then move initializers to it.

* review fixes
This commit is contained in:
Igor Chevdar
2017-03-10 19:02:02 +05:00
committed by GitHub
parent 1f9d41b291
commit ed2191b4a3
4 changed files with 76 additions and 25 deletions
@@ -25,12 +25,12 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile)
}
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
SharedVariablesLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
SharedVariablesLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_DELEGATION) {
PropertyDelegationLowering(context).lower(irFile)
}
@@ -12,14 +12,14 @@ enum class KonanPhase(val description: String,
/* ... */ LOWER("IR Lowering"),
/* ... ... */ LOWER_INLINE("Functions inlining"),
/* ... ... */ LOWER_INTEROP("Interop lowering"),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", setOf(LOWER_ENUMS)),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", setOf(LOWER_INITIALIZERS)),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", setOf(
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION)),
/* ... ... */ LOWER_VARARG("Vararg lowering", setOf(LOWER_CALLABLES)),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", setOf(LOWER_INITIALIZERS)),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", setOf(LOWER_SHARED_VARIABLES)),
/* ... ... */ LOWER_TAILREC("tailrec lowering", setOf(LOWER_LOCAL_FUNCTIONS)),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", setOf(
LOWER_TAILREC, LOWER_ENUMS)),
@@ -126,11 +126,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
declaration.transformChildrenVoid(this)
val blockBody = declaration.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.descriptor))
else null
if (blockBody.statements.all { it !is IrInstanceInitializerCall }) {
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.descriptor))
else null
}
}
return declaration
}
@@ -173,6 +175,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
val constructors = mutableSetOf<ClassConstructorDescriptor>()
var primaryConstructor: ClassConstructorDescriptor? = null
descriptor.constructors.forEach {
val loweredEnumConstructor = loweredEnumConstructors[it]!!
@@ -181,6 +184,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
constructors.add(constructorDescriptor)
defaultClass.declarations.add(constructor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
if (loweredEnumConstructor.isPrimary)
primaryConstructor = constructorDescriptor
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
if (irConstructor != null) {
@@ -194,7 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
val memberScope = SimpleMemberScope(irClass.descriptor.unsubstitutedMemberScope.getContributedDescriptors().toList())
defaultClassDescriptor.initialize(memberScope, constructors, null)
defaultClassDescriptor.initialize(memberScope, constructors, primaryConstructor)
return defaultClass
}
@@ -2,18 +2,22 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.konan.Context
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.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
internal class InitializersLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
@@ -25,12 +29,16 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
fun lowerInitializers() {
collectAndRemoveInitializers()
lowerConstructors()
val initializerMethodDescriptor = createInitializerMethod()
lowerConstructors(initializerMethodDescriptor)
}
object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER :
IrStatementOriginImpl("ANONYMOUS_INITIALIZER")
object DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER :
IrDeclarationOriginImpl("ANONYMOUS_INITIALIZER")
private fun collectAndRemoveInitializers() {
// Do with one traversal in order to preserve initializers order.
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
@@ -67,8 +75,35 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
}
}
private fun lowerConstructors() {
private fun createInitializerMethod(): FunctionDescriptor? {
if (irClass.descriptor.hasPrimaryConstructor())
return null // Place initializers in the primary constructor.
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ irClass.descriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ "INITIALIZER".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
initializerMethodDescriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ irClass.descriptor.thisAsReceiverParameter,
/* typeParameters = */ listOf(),
/* unsubstitutedValueParameters = */ listOf(),
/* returnType = */ context.builtIns.unitType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE)
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val initializer = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
initializerMethodDescriptor, IrBlockBodyImpl(startOffset, endOffset, initializers))
irClass.declarations.add(initializer)
return initializerMethodDescriptor
}
private fun lowerConstructors(initializerMethodDescriptor: FunctionDescriptor?) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// Skip nested.
return declaration
@@ -79,15 +114,26 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.transformFlat {
when {
it is IrInstanceInitializerCall -> initializers
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
it is IrInstanceInitializerCall -> {
if (initializerMethodDescriptor == null) {
assert(declaration.descriptor.isPrimary)
initializers
} else {
val startOffset = it.startOffset
val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset, initializerMethodDescriptor).apply {
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter)
})
}
}
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any
&& it.descriptor == declaration.descriptor -> listOf()
else -> null