Move fields and init blocks of companions to their owners

This commit is contained in:
Georgy Bronnikov
2018-07-19 18:14:58 +03:00
parent 827494abbe
commit 605afbae90
42 changed files with 567 additions and 176 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -200,6 +201,7 @@ open class WrappedVariableDescriptor(
override fun getContainingDeclaration() = (owner.parent as IrFunction).descriptor
override fun getType() = owner.type.toKotlinType()
override fun getReturnType() = getType()
override fun getName() = owner.name
override fun isConst() = owner.isConst
override fun isVar() = owner.isVar
@@ -489,7 +491,7 @@ open class WrappedPropertyDescriptor(
annotations: Annotations = Annotations.EMPTY,
private val sourceElement: SourceElement = SourceElement.NO_SOURCE
) : PropertyDescriptor, WrappedDeclarationDescriptor<IrField>(annotations) {
override fun getModality() = if (owner.isFinal) Modality.FINAL else Modality.OPEN
override fun getModality() = owner.correspondingProperty?.modality ?: Modality.FINAL
override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection<out CallableMemberDescriptor>) {
TODO("not implemented")
@@ -553,21 +555,18 @@ open class WrappedPropertyDescriptor(
override fun getType(): KotlinType = owner.type.toKotlinType()
override fun isVar() = owner.isFinal
override fun isVar() = !owner.isFinal
override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? {
TODO("not implemented")
}
override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? =
if (owner.isStatic) null else (owner.parentAsClass.thisReceiver?.descriptor as ReceiverParameterDescriptor)
override fun isConst() = false
override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor
override fun isLateInit() = false
override fun isLateInit() = owner.correspondingProperty?.isLateinit ?: false
override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? {
TODO("not implemented")
}
override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = owner.correspondingProperty?.descriptor?.extensionReceiverParameter
override fun isExternal() = owner.isExternal
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import java.io.StringWriter
@@ -303,3 +304,21 @@ fun IrType.remapTypeParameters(source: IrTypeParametersContainer, target: IrType
else -> this
}
/* Copied from K/N */
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
this.declarations += declaration
declaration.accept(SetDeclarationsParentVisitor, this)
}
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) {
element.acceptChildren(this, data)
}
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) {
declaration.parent = data
super.visitDeclaration(declaration, data)
}
}
@@ -7,34 +7,29 @@ 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.ir.SetDeclarationsParentVisitor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
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.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
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.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import java.util.*
object SYNTHESIZED_INIT_BLOCK: IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
class InitializersLowering(
val context: CommonBackendContext,
@@ -42,83 +37,101 @@ class InitializersLowering(
private val clinitNeeded: Boolean
) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val classInitializersBuilder = ClassInitializersBuilder(irClass)
irClass.acceptChildrenVoid(classInitializersBuilder)
val instanceInitializerStatements = handleNonStatics(irClass)
transformInstanceInitializerCallsInConstructors(irClass, instanceInitializerStatements)
classInitializersBuilder.transformInstanceInitializerCallsInConstructors(irClass)
if (clinitNeeded && classInitializersBuilder.staticInitializerStatements.isNotEmpty())
classInitializersBuilder.createStaticInitializationMethod(irClass)
val staticInitializerStatements = handleStatics(irClass)
if (clinitNeeded && staticInitializerStatements.isNotEmpty())
createStaticInitializationMethod(irClass, staticInitializerStatements)
}
private inner class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid {
val staticInitializerStatements = ArrayList<IrStatement>()
fun handleNonStatics(irClass: IrClass) =
irClass.declarations.filter {
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
}.mapNotNull { handleDeclaration(irClass, it) }
val instanceInitializerStatements = ArrayList<IrStatement>()
fun handleStatics(irClass: IrClass) =
// 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)
})
.mapNotNull { handleDeclaration(irClass, it) }
override fun visitElement(element: IrElement) {
// skip everything else
}
fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when(declaration) {
is IrField -> handleField(irClass, declaration)
is IrAnonymousInitializer -> handleAnonymousInitializer(declaration)
else -> null
}
override fun visitField(declaration: IrField) {
val irFieldInitializer = declaration.initializer?.expression ?: return
fun handleField(irClass: IrClass, declaration: IrField): IrStatement? {
val irFieldInitializer = declaration.initializer?.expression ?: return null
val receiver =
if (!declaration.isStatic) // TODO isStaticField
IrGetValueImpl(
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
)
else null
val irSetField = IrSetFieldImpl(
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
declaration.symbol,
receiver,
irFieldInitializer,
context.irBuiltIns.unitType,
null, null
)
if (declaration.isStatic) {
staticInitializerStatements.add(irSetField)
} else {
instanceInitializerStatements.add(irSetField)
}
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
instanceInitializerStatements.addAll(declaration.body.statements)
}
fun transformInstanceInitializerCallsInConstructors(irClass: IrClass) {
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)
}
})
}
fun createStaticInitializationMethod(irClass: IrClass) {
val staticInitializerDescriptor = SimpleFunctionDescriptorImpl.create(
irClass.descriptor, Annotations.EMPTY, clinitName,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
)
staticInitializerDescriptor.initialize(
null, null, emptyList(), emptyList(),
irClass.descriptor.builtIns.unitType,
Modality.FINAL, Visibilities.PUBLIC
)
irClass.declarations.add(
IrFunctionImpl(
irClass.startOffset, irClass.endOffset, declarationOrigin,
staticInitializerDescriptor,
IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
staticInitializerStatements.map { it.copy(irClass) })
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
)
}
fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = IrBlockImpl(
declaration.startOffset, declaration.endOffset,
context.irBuiltIns.unitType,
SYNTHESIZED_INIT_BLOCK,
declaration.body.statements
)
fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List<IrStatement>) {
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)
}
})
}
fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List<IrStatement>) {
val staticInitializerDescriptor = SimpleFunctionDescriptorImpl.create(
irClass.descriptor, Annotations.EMPTY, clinitName,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
)
staticInitializerDescriptor.initialize(
null, null, emptyList(), emptyList(),
irClass.descriptor.builtIns.unitType,
Modality.FINAL, Visibilities.PUBLIC
)
irClass.declarations.add(
IrFunctionImpl(
irClass.startOffset, irClass.endOffset, declarationOrigin,
staticInitializerDescriptor,
IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
staticInitializerStatements.map { it.copy(irClass) })
).apply {
returnType = context.irBuiltIns.unitType
accept(SetDeclarationsParentVisitor, this)
}
)
}
companion object {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
@@ -33,6 +34,8 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -235,3 +238,30 @@ fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index
)
else -> throw Error("Unexpected parameter descriptor: $this")
}
fun IrBody.replaceThisByStaticReference(
context: CommonBackendContext,
irClass: IrClass,
oldThisReceiverParameter: IrValueParameter
): IrBody =
transform(ReplaceThisByStaticReference(context, irClass, oldThisReceiverParameter), null)
private class ReplaceThisByStaticReference(
val context: CommonBackendContext,
val irClass: IrClass,
val oldThisReceiverParameter: IrValueParameter
) : IrElementTransformer<Nothing?> {
override fun visitGetValue(expression: IrGetValue, data: Nothing?): IrExpression {
val irGetValue = expression
if (irGetValue.symbol == oldThisReceiverParameter.symbol) {
val instanceField = context.declarationFactory.getFieldForObjectInstance(irClass)
return IrGetFieldImpl(
expression.startOffset,
expression.endOffset,
instanceField.symbol,
irClass.defaultType
)
}
return super.visitGetValue(irGetValue, data)
}
}
@@ -36,7 +36,8 @@ class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List<IrDeclaration>? =
if (declaration is IrProperty)
ArrayList<IrDeclaration>(3).apply {
if (kind != ClassKind.ANNOTATION_CLASS) {
// JvmFields in a companion object refer to companion's owners and should not be generated within companion.
if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) {
addIfNotNull(declaration.backingField)
}
addIfNotNull(declaration.getter)