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:
+3
-3
@@ -25,12 +25,12 @@ internal class KonanLower(val context: Context) {
|
|||||||
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
||||||
EnumClassLowering(context).run(irFile)
|
EnumClassLowering(context).run(irFile)
|
||||||
}
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
|
|
||||||
SharedVariablesLowering(context).runOnFilePostfix(irFile)
|
|
||||||
}
|
|
||||||
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
||||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
|
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
|
||||||
|
SharedVariablesLowering(context).runOnFilePostfix(irFile)
|
||||||
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_DELEGATION) {
|
phaser.phase(KonanPhase.LOWER_DELEGATION) {
|
||||||
PropertyDelegationLowering(context).lower(irFile)
|
PropertyDelegationLowering(context).lower(irFile)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -12,14 +12,14 @@ enum class KonanPhase(val description: String,
|
|||||||
/* ... */ LOWER("IR Lowering"),
|
/* ... */ LOWER("IR Lowering"),
|
||||||
/* ... ... */ LOWER_INLINE("Functions inlining"),
|
/* ... ... */ LOWER_INLINE("Functions inlining"),
|
||||||
/* ... ... */ LOWER_INTEROP("Interop lowering"),
|
/* ... ... */ LOWER_INTEROP("Interop lowering"),
|
||||||
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering"),
|
|
||||||
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
|
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
|
||||||
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
|
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
|
||||||
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", setOf(LOWER_ENUMS)),
|
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", setOf(LOWER_ENUMS)),
|
||||||
|
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", setOf(LOWER_INITIALIZERS)),
|
||||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", setOf(
|
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", setOf(
|
||||||
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION)),
|
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION)),
|
||||||
/* ... ... */ LOWER_VARARG("Vararg lowering", setOf(LOWER_CALLABLES)),
|
/* ... ... */ 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_TAILREC("tailrec lowering", setOf(LOWER_LOCAL_FUNCTIONS)),
|
||||||
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", setOf(
|
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", setOf(
|
||||||
LOWER_TAILREC, LOWER_ENUMS)),
|
LOWER_TAILREC, LOWER_ENUMS)),
|
||||||
|
|||||||
+11
-6
@@ -126,11 +126,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
declaration.transformChildrenVoid(this)
|
declaration.transformChildrenVoid(this)
|
||||||
|
|
||||||
val blockBody = declaration.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
|
val blockBody = declaration.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
|
||||||
blockBody.statements.transformFlat {
|
if (blockBody.statements.all { it !is IrInstanceInitializerCall }) {
|
||||||
if (it is IrEnumConstructorCall)
|
blockBody.statements.transformFlat {
|
||||||
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
|
if (it is IrEnumConstructorCall)
|
||||||
irClass.descriptor))
|
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
|
||||||
else null
|
irClass.descriptor))
|
||||||
|
else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
@@ -173,6 +175,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
|
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
|
||||||
|
|
||||||
val constructors = mutableSetOf<ClassConstructorDescriptor>()
|
val constructors = mutableSetOf<ClassConstructorDescriptor>()
|
||||||
|
var primaryConstructor: ClassConstructorDescriptor? = null
|
||||||
|
|
||||||
descriptor.constructors.forEach {
|
descriptor.constructors.forEach {
|
||||||
val loweredEnumConstructor = loweredEnumConstructors[it]!!
|
val loweredEnumConstructor = loweredEnumConstructors[it]!!
|
||||||
@@ -181,6 +184,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
constructors.add(constructorDescriptor)
|
constructors.add(constructorDescriptor)
|
||||||
defaultClass.declarations.add(constructor)
|
defaultClass.declarations.add(constructor)
|
||||||
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
|
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
|
||||||
|
if (loweredEnumConstructor.isPrimary)
|
||||||
|
primaryConstructor = constructorDescriptor
|
||||||
|
|
||||||
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
|
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
|
||||||
if (irConstructor != null) {
|
if (irConstructor != null) {
|
||||||
@@ -194,7 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val memberScope = SimpleMemberScope(irClass.descriptor.unsubstitutedMemberScope.getContributedDescriptors().toList())
|
val memberScope = SimpleMemberScope(irClass.descriptor.unsubstitutedMemberScope.getContributedDescriptors().toList())
|
||||||
defaultClassDescriptor.initialize(memberScope, constructors, null)
|
defaultClassDescriptor.initialize(memberScope, constructors, primaryConstructor)
|
||||||
|
|
||||||
return defaultClass
|
return defaultClass
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-14
@@ -2,18 +2,22 @@ package org.jetbrains.kotlin.backend.konan.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
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.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.IrBlockBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
|
||||||
|
|
||||||
internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
@@ -25,12 +29,16 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
|||||||
|
|
||||||
fun lowerInitializers() {
|
fun lowerInitializers() {
|
||||||
collectAndRemoveInitializers()
|
collectAndRemoveInitializers()
|
||||||
lowerConstructors()
|
val initializerMethodDescriptor = createInitializerMethod()
|
||||||
|
lowerConstructors(initializerMethodDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER :
|
object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER :
|
||||||
IrStatementOriginImpl("ANONYMOUS_INITIALIZER")
|
IrStatementOriginImpl("ANONYMOUS_INITIALIZER")
|
||||||
|
|
||||||
|
object DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER :
|
||||||
|
IrDeclarationOriginImpl("ANONYMOUS_INITIALIZER")
|
||||||
|
|
||||||
private fun collectAndRemoveInitializers() {
|
private fun collectAndRemoveInitializers() {
|
||||||
// Do with one traversal in order to preserve initializers order.
|
// Do with one traversal in order to preserve initializers order.
|
||||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
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() {
|
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement {
|
override fun visitClass(declaration: IrClass): IrStatement {
|
||||||
// Skip nested.
|
// Skip nested.
|
||||||
return declaration
|
return declaration
|
||||||
@@ -79,15 +114,26 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
|
|||||||
|
|
||||||
blockBody.statements.transformFlat {
|
blockBody.statements.transformFlat {
|
||||||
when {
|
when {
|
||||||
it is IrInstanceInitializerCall -> initializers
|
it is IrInstanceInitializerCall -> {
|
||||||
/**
|
if (initializerMethodDescriptor == null) {
|
||||||
* IR for kotlin.Any is:
|
assert(declaration.descriptor.isPrimary)
|
||||||
* BLOCK_BODY
|
initializers
|
||||||
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
} else {
|
||||||
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
|
val startOffset = it.startOffset
|
||||||
*
|
val endOffset = it.endOffset
|
||||||
* to avoid possible recursion we manually reject body generation for Any.
|
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 is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any
|
||||||
&& it.descriptor == declaration.descriptor -> listOf()
|
&& it.descriptor == declaration.descriptor -> listOf()
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
Reference in New Issue
Block a user