diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index 3411f25f569..e5b782822df 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -7,10 +7,9 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl @@ -18,73 +17,51 @@ 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.util.deepCopyWithSymbols -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK") -open class InitializersLowering( - context: CommonBackendContext -) : InitializersLoweringBase(context) { +open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) { override fun lower(irClass: IrClass) { - val nonStaticDeclarations = getDeclarationsWithNonStaticInitializers(irClass) - val instanceInitializerStatements = nonStaticDeclarations.mapNotNull { handleDeclaration(irClass, it) } - transformInstanceInitializerCallsInConstructors(irClass, instanceInitializerStatements) - - val anonymousInitializers = nonStaticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer } - irClass.declarations.removeAll(anonymousInitializers) - } - - private fun getDeclarationsWithNonStaticInitializers(irClass: IrClass): List = - irClass.declarations.filter { + val instanceInitializerStatements = extractInitializers(irClass) { (it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic) } + irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { + // Only transform constructors of current class. + override fun visitClassNew(declaration: IrClass) = declaration - private fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List) { - irClass.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression { - val copiedBlock = - IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements) - .copy(irClass) as IrBlock - return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements) - } + override fun visitSimpleFunction(declaration: IrSimpleFunction) = declaration + + override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression = + IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements) + .deepCopyWithSymbols(currentScope!!.scope.getLocalDeclarationParent()) }) } } abstract class InitializersLoweringBase(val context: CommonBackendContext) : ClassLoweringPass { - protected fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when (declaration) { - is IrField -> handleField(irClass, declaration) - is IrAnonymousInitializer -> handleAnonymousInitializer(declaration) - else -> null - } + protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) = + irClass.declarations.filter(filter).mapNotNull { + when (it) { + is IrField -> handleField(irClass, it) + is IrAnonymousInitializer -> handleAnonymousInitializer(it) + else -> null + } + }.also { + irClass.declarations.removeAll { it is IrAnonymousInitializer && filter(it) } + } - private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? { - val irFieldInitializer = declaration.initializer?.expression ?: return null + private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? = + declaration.initializer?.run { + val receiver = if (!declaration.isStatic) // TODO isStaticField + IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol) + else + null + IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType) + } - val receiver = - if (!declaration.isStatic) // TODO isStaticField - IrGetValueImpl( - irFieldInitializer.startOffset, irFieldInitializer.endOffset, - irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol - ) - else null - return IrSetFieldImpl( - irFieldInitializer.startOffset, irFieldInitializer.endOffset, - declaration.symbol, - receiver, - irFieldInitializer, - context.irBuiltIns.unitType, - null, null - ) - } - - private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = IrBlockImpl( - declaration.startOffset, declaration.endOffset, - context.irBuiltIns.unitType, - SYNTHESIZED_INIT_BLOCK, - declaration.body.statements - ) - - protected fun IrStatement.copy(containingDeclaration: IrDeclarationParent): IrStatement = deepCopyWithSymbols(containingDeclaration) + private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = + with(declaration) { + IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements) + } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt index df959857f6d..83d74c6b8b1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt @@ -6,74 +6,46 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.Visibilities -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.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.ir.builders.declarations.addFunction +import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.expressions.IrSetField import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.name.Name class StaticInitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) { override fun lower(irClass: IrClass) { - val staticDeclarations = getDeclarationsWithStaticInitializers(irClass) - val staticInitializerStatements = staticDeclarations.mapNotNull { handleDeclaration(irClass, it) } + val staticInitializerStatements = extractInitializers(irClass) { + (it is IrField && it.isStatic) || (it is IrAnonymousInitializer && it.isStatic) + }.toMutableList() if (staticInitializerStatements.isNotEmpty()) { - createStaticInitializationMethod(irClass, staticInitializerStatements) - - val anonymousInitializers = staticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer } - irClass.declarations.removeAll(anonymousInitializers) + staticInitializerStatements.sortBy { + when ((it as? IrSetField)?.symbol?.owner?.origin) { + IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY -> 1 + IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES -> 2 + IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE -> 3 + else -> 4 + } + } + irClass.addFunction { + startOffset = irClass.startOffset + endOffset = irClass.endOffset + name = clinitName + // TODO: mark as synthesized + origin = JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER + returnType = context.irBuiltIns.unitType + }.apply { + body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset, staticInitializerStatements) + .deepCopyWithSymbols(this) + } } } - private fun getDeclarationsWithStaticInitializers(irClass: IrClass): List = - // Hardcoded order of initializers - (irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY } + - irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES } + - irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE } + - irClass.declarations.filter { - (it is IrField && it.isStatic && it.origin !in listOf( - IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY, - IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES, - IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE - )) || (it is IrAnonymousInitializer && it.isStatic) - }) - - private fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List) { - // TODO: mark as synthesized - val staticInitializerDescriptor = WrappedSimpleFunctionDescriptor() - val staticInitializer = IrFunctionImpl( - irClass.startOffset, - irClass.endOffset, - JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, - IrSimpleFunctionSymbolImpl(staticInitializerDescriptor), - clinitName, - Visibilities.PUBLIC, - Modality.FINAL, - returnType = context.irBuiltIns.unitType, - isInline = false, - isExternal = false, - isTailrec = false, - isSuspend = false, - isExpect = false, - isFakeOverride = false, - isOperator = false - ).apply { - staticInitializerDescriptor.bind(this) - body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset, - staticInitializerStatements.map { it.copy(irClass) }) - accept(SetDeclarationsParentVisitor, this) - // Should come after SetDeclarationParentVisitor, because it sets staticInitializer's own parent to itself. - parent = irClass - } - irClass.declarations.add(staticInitializer) - } - companion object { val clinitName = Name.special("") }