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) {
|
||||
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)
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)),
|
||||
|
||||
+11
-6
@@ -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
|
||||
}
|
||||
|
||||
+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.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
|
||||
|
||||
Reference in New Issue
Block a user