Some enum-related fixes

(NB: testEnumClass3 doesn't work yet, effective modality required for enum class)
This commit is contained in:
Dmitry Petrov
2016-09-28 17:34:44 +03:00
parent de2bef910b
commit 608d6a37d2
12 changed files with 176 additions and 41 deletions
@@ -34,7 +34,7 @@ class JvmLower(val context: JvmBackendContext) {
InterfaceDelegationLowering(context.state).runOnFile(irFile)
EnumClassLowering(context).runOnFile(irFile)
ObjectClassLowering(context).runOnFile(irFile)
InitializersLowering().runOnFile(irFile)
InitializersLowering(context).runOnFile(irFile)
SingletonReferencesLowering(context).runOnFile(irFile)
}
}
@@ -154,7 +154,7 @@ private fun MemberDescriptor.calcModalityFlag(): Int {
flags = flags.or(Opcodes.ACC_ABSTRACT)
}
Modality.FINAL -> {
if (this !is ConstructorDescriptor) {
if (this !is ConstructorDescriptor && !DescriptorUtils.isEnumClass(this)) {
flags = flags.or(Opcodes.ACC_FINAL)
}
}
@@ -172,6 +172,11 @@ private fun MemberDescriptor.calcModalityFlag(): Int {
return flags
}
//val MemberDescriptor.effectiveModality: Modality
// get() {
//
// }
val DeclarationDescriptorWithSource.psiElement: PsiElement?
get() = (source as? PsiSourceElement)?.psi
@@ -56,6 +56,7 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
private interface EnumConstructorCallTransformer {
fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression
fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression
}
private val unsubstitutedArrayOfFun = context.builtIns.findSingleFunction(Name.identifier("arrayOf"))
@@ -286,6 +287,28 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
return result
}
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
val descriptor = delegatingConstructorCall.descriptor
val startOffset = delegatingConstructorCall.startOffset
val endOffset = delegatingConstructorCall.endOffset
val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(descriptor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
}
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredDelegatedConstructor)
result.putValueArgument(0, IrGetVariableImpl(startOffset, endOffset, enumClassConstructor.valueParameters[0]))
result.putValueArgument(1, IrGetVariableImpl(startOffset, endOffset, enumClassConstructor.valueParameters[1]))
descriptor.valueParameters.forEach { valueParameter ->
val i = valueParameter.index
result.putValueArgument(i + 2, delegatingConstructorCall.getValueArgument(i))
}
return result
}
}
private abstract inner class InEnumEntry(private val enumEntry: ClassDescriptor) : EnumConstructorCallTransformer {
@@ -314,6 +337,10 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
return result
}
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
throw AssertionError("Unexpected delegating constructor call within enum entry: $enumEntry")
}
abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: ClassConstructorDescriptor): IrMemberAccessExpression
}
@@ -331,8 +358,11 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
override fun visitField(declaration: IrField): IrStatement {
val enumEntry = enumEntriesByField[declaration.descriptor] ?:
return declaration
val enumEntry = enumEntriesByField[declaration.descriptor]
if (enumEntry == null) {
declaration.transformChildrenVoid(this)
return declaration
}
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}"}
@@ -378,10 +408,29 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
return callTransformer.transform(expression)
}
override fun visitGetVariable(expression: IrGetVariable): IrExpression =
loweredEnumConstructorParameters[expression.descriptor]?.let { loweredParameter ->
IrGetVariableImpl(expression.startOffset, expression.endOffset, loweredParameter, expression.origin)
} ?: expression
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.descriptor.containingDeclaration.kind == ClassKind.ENUM_CLASS) {
val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" +
irClass.dump())
return callTransformer.transform(expression)
}
return expression
}
override fun visitGetVariable(expression: IrGetVariable): IrExpression {
val loweredParameter = loweredEnumConstructorParameters[expression.descriptor]
if (loweredParameter != null) {
return IrGetVariableImpl(expression.startOffset, expression.endOffset, loweredParameter, expression.origin)
}
else {
return expression
}
}
override fun visitSyntheticBody(body: IrSyntheticBody): IrBody {
return when (body.kind) {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.getMemberOwnerKind
import org.jetbrains.kotlin.codegen.AsmUtil
@@ -35,15 +36,18 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrThisReferenceImpl
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.util.dump
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.*
class InitializersLowering : ClassLoweringPass {
class InitializersLowering(val context: JvmBackendContext) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val classInitializersBuilder = ClassInitializersBuilder(irClass)
irClass.acceptChildrenVoid(classInitializersBuilder)
@@ -53,9 +57,7 @@ class InitializersLowering : ClassLoweringPass {
classInitializersBuilder.createStaticInitializationMethod(irClass)
}
private class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid {
val classMemberOwnerKind = irClass.descriptor.getMemberOwnerKind()
private inner class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid {
val staticInitializerStatements = ArrayList<IrStatement>()
val instanceInitializerStatements = ArrayList<IrStatement>()
@@ -65,7 +67,7 @@ class InitializersLowering : ClassLoweringPass {
}
override fun visitField(declaration: IrField) {
val irFieldInitializer = declaration.initializer?.let { it.expression } ?: return
val irFieldInitializer = declaration.initializer?.expression ?: return
val receiver =
if (declaration.descriptor.dispatchReceiverParameter != null) // TODO isStaticField
@@ -93,23 +95,12 @@ class InitializersLowering : ClassLoweringPass {
}
fun transformInstanceInitializerCallsInConstructors(irClass: IrClass) {
for (irDeclaration in irClass.declarations) {
if (irDeclaration !is IrConstructor) continue
val irBody = irDeclaration.body as IrBlockBody
if (irBody.statements.any { it is IrInstanceInitializerCall }) {
val newStatements = irBody.statements.map { irStatement ->
if (irStatement is IrInstanceInitializerCall) {
IrBlockImpl(irClass.startOffset, irClass.endOffset, irDeclaration.descriptor.builtIns.unitType, null,
instanceInitializerStatements.map { it.copy() })
}
else {
irStatement
}
}
irBody.statements.clear()
irBody.statements.addAll(newStatements)
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.builtIns.unitType, null,
instanceInitializerStatements.map { it.copy() })
}
}
})
}
fun createStaticInitializationMethod(irClass: IrClass) {
@@ -235,7 +235,7 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
}
private fun generateEnumEntrySuperConstructorCall(ktEnumEntry: KtEnumEntry, enumEntryDescriptor: ClassDescriptor): IrExpression {
return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor, null)
return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor)
}
fun generateAnonymousInitializerBody(ktAnonymousInitializer: KtAnonymousInitializer): IrBlockBody {
@@ -256,13 +256,12 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumEntryConstructor)
}
return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor, enumEntryDescriptor)
return generateEnumConstructorCallOrSuperCall(ktEnumEntry, enumEntryDescriptor.containingDeclaration as ClassDescriptor)
}
private fun generateEnumConstructorCallOrSuperCall(
ktEnumEntry: KtEnumEntry,
enumClassDescriptor: ClassDescriptor,
enumEntryOrNull: ClassDescriptor?
enumClassDescriptor: ClassDescriptor
): IrExpression {
val statementGenerator = createStatementGenerator()
@@ -271,12 +270,12 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
val enumConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperCallElement)!!)
return CallGenerator(statementGenerator).generateEnumConstructorSuperCall(
ktEnumEntry.startOffset, ktEnumEntry.endOffset,
enumConstructorCall, enumEntryOrNull)
enumConstructorCall)
}
// No-argument enum entry constructor
val enumClassConstructor = enumClassDescriptor.unsubstitutedPrimaryConstructor!!
val enumClassConstructor = enumClassDescriptor.constructors.find { it.valueParameters.isEmpty() }!!
return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumClassConstructor)
}
@@ -68,8 +68,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
}
}
fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder,
enumEntryDescriptor: ClassDescriptor?) : IrExpression {
fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder) : IrExpression {
val constructorDescriptor = call.descriptor
if (constructorDescriptor !is ClassConstructorDescriptor) throw AssertionError("Constructor expected: $constructorDescriptor")
val classDescriptor = constructorDescriptor.containingDeclaration