Split up EnumClassLowering on two parts

EnumConstructorsLowering will be moved to common part
Also moved EnumClassLowering down along the pipeline
This commit is contained in:
Igor Chevdar
2019-01-25 17:29:42 +03:00
parent 9757a715f7
commit 68530bf28b
8 changed files with 451 additions and 468 deletions
@@ -83,8 +83,8 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_FOR_LOOPS) {
ForLoopsLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile)
phaser.phase(KonanPhase.LOWER_ENUM_CONSTRUCTORS) {
EnumConstructorsLowering(context).run(irFile)
}
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
@@ -117,6 +117,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
InnerClassLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile)
}
phaser.phase(KonanPhase.LOWER_INTEROP_PART2) {
InteropLoweringPart2(context).lower(irFile)
}
@@ -29,9 +29,10 @@ enum class KonanPhase(val description: String,
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
/* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE),
/* ... ... */ LOWER_FOR_LOOPS("For loops lowering"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_ENUM_CONSTRUCTORS("Enum constructors lowering"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering", LOWER_ENUM_CONSTRUCTORS),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUM_CONSTRUCTORS),
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering", LOWER_INLINE),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_DELEGATION),
@@ -39,7 +40,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUMS),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUM_CONSTRUCTORS),
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES, LOWER_DEFAULT_PARAMETER_EXTENT),
/* ... ... */ LOWER_COMPILE_TIME_EVAL("Compile time evaluation lowering", LOWER_VARARG, enabled = false),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT, GEN_SYNTHETIC_FIELDS),
@@ -100,7 +100,6 @@ internal val IrClass.isInterface: Boolean
get() = (this.kind == ClassKind.INTERFACE)
fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
internal fun IrFunction.hasValueTypeAt(index: Int): Boolean {
when (index) {
@@ -134,7 +134,6 @@ internal val MemberScope.contributedMethods: List<FunctionDescriptor>
}
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
internal val FunctionDescriptor.target: FunctionDescriptor
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
@@ -131,7 +131,7 @@ val IrFunction.isOverridableOrOverrides
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
val IrClass.isFinalClass: Boolean
get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
get() = modality == Modality.FINAL
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
if (this == other) return true
@@ -7,21 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
@@ -29,17 +21,10 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
@@ -163,111 +148,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
EnumClassTransformer(irClass).run()
}
private interface EnumConstructorCallTransformer {
fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression
fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression
}
private inner class EnumClassTransformer(val irClass: IrClass) {
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass)
private val loweredEnumConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val loweredEnumConstructorParameters = mutableMapOf<IrValueParameter, IrValueParameter>()
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
fun run() {
insertInstanceInitializerCall()
lowerEnumConstructors(irClass)
lowerEnumEntriesClasses()
val defaultClass = createDefaultClassForEnumEntries()
lowerEnumClassBody(defaultClass)
pullUpEnumEntriesClasses()
createImplObject()
}
private fun insertInstanceInitializerCall() {
irClass.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// Skip nested
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
declaration.transformChildrenVoid(this)
val blockBody = declaration.body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
if (blockBody.statements.all { it !is IrInstanceInitializerCall }) {
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.symbol, context.irBuiltIns.unitType))
else null
}
}
return declaration
}
})
}
private fun lowerEnumEntriesClasses() {
private fun pullUpEnumEntriesClasses() {
irClass.declarations.transformFlat { declaration ->
if (declaration is IrEnumEntry) {
listOfNotNull(declaration, lowerEnumEntryClass(declaration.correspondingClass))
val correspondingClass = declaration.correspondingClass
declaration.correspondingClass = null
listOfNotNull(declaration, correspondingClass)
} else null
}
}
private fun lowerEnumEntryClass(enumEntryClass: IrClass?): IrClass? {
if (enumEntryClass == null) return null
lowerEnumConstructors(enumEntryClass)
return enumEntryClass
}
private fun createDefaultClassForEnumEntries(): IrClass? {
if (!irClass.declarations.any { it is IrEnumEntry && it.correspondingClass == null }) return null
val defaultClass = WrappedClassDescriptor().let {
IrClassImpl(
irClass.startOffset, irClass.endOffset,
DECLARATION_ORIGIN_ENUM,
IrClassSymbolImpl(it),
"DEFAULT".synthesizedName,
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = irClass
irClass.declarations += this
createParameterDeclarations()
}
}
for (superConstructor in irClass.constructors) {
val constructor = defaultClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns)
defaultEnumEntryConstructors[superConstructor] = constructor
for (parameter in constructor.valueParameters) {
val defaultValue = superConstructor.valueParameters[parameter.index].defaultValue ?: continue
val body = defaultValue.deepCopyWithVariables()
body.transformChildrenVoid(ParameterMapper(superConstructor, constructor, false))
body.patchDeclarationParents(constructor)
parameter.defaultValue = body
}
}
defaultClass.superTypes += irClass.defaultType
defaultClass.addFakeOverrides()
return defaultClass
}
private fun createImplObject() {
val implObject = loweredEnum.implObject
@@ -300,7 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
implObject.declarations += createValuesPropertyInitializer(enumEntries)
irClass.declarations += implObject
}
@@ -311,6 +210,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val implObject = loweredEnum.implObject
val constructor = implObject.constructors.single()
val irValuesInitializer = context.createArrayOfExpression(
startOffset, endOffset,
irClass.defaultType,
@@ -335,31 +237,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
)
val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
val irField = loweredEnum.valuesField
context.createIrBuilder(constructor.symbol).run {
(constructor.body as IrBlockBody).statements +=
irSetField(irGet(implObject.thisReceiver!!), irField, irValuesInitializer)
}
val getter = loweredEnum.valuesGetter
context.createIrBuilder(getter.symbol).run {
getter.body = irBlockBody(irClass) { +irReturn(irGetField(irGetObject(implObject.symbol), irField)) }
}
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
val value = IrGetFieldImpl(
startOffset, endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
)
val returnStatement = IrReturnImpl(
startOffset, endOffset,
context.irBuiltIns.nothingType,
loweredEnum.valuesGetter.symbol,
value
)
getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
createValuesPropertyInitializer(enumEntries)
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
false, loweredEnum.valuesField.descriptor, irField, getter, null).apply {
parent = loweredEnum.implObject
parent = implObject
}
}
@@ -369,54 +262,50 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>): IrAnonymousInitializerImpl {
private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>) {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
irCall(initInstanceSymbol).apply {
putValueArgument(0, instance)
putValueArgument(1, constructor)
}
val implObject = loweredEnum.implObject
return IrAnonymousInitializerImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor())
).apply {
parent = implObject
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) {
val receiver = implObject.thisReceiver!!
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
enumEntries
.sortedBy { it.name }
.withIndex()
.forEach {
val instance = irCall(arrayGetSymbol).apply {
dispatchReceiver = irGet(instances)
putValueArgument(0, irInt(it.index))
}
val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(implObject)
when {
initializer is IrCall -> +initInstanceCall(instance, initializer)
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
val statements = initializer.statements
val constructorCall = statements.last() as IrCall
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
+initializer
}
else -> error("Unexpected initializer: $initializer")
}
val constructor = implObject.constructors.single()
val irBuilder = context.createIrBuilder(constructor.symbol, startOffset, endOffset)
val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) {
val receiver = implObject.thisReceiver!!
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
enumEntries
.sortedBy { it.name }
.withIndex()
.forEach {
val instance = irCall(arrayGetSymbol).apply {
dispatchReceiver = irGet(instances)
putValueArgument(0, irInt(it.index))
}
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
extensionReceiver = irGet(receiver)
}
val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(constructor)
when {
initializer is IrCall -> +initInstanceCall(instance, initializer)
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
val statements = initializer.statements
val constructorCall = statements.last() as IrCall
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
+initializer
}
else -> error("Unexpected initializer: $initializer")
}
}
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
extensionReceiver = irGet(receiver)
}
}
(constructor.body as IrBlockBody).statements += valuesInitializer
}
private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody {
@@ -453,302 +342,5 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
}
private fun lowerEnumConstructors(irClass: IrClass) {
irClass.declarations.forEachIndexed { index, declaration ->
if (declaration is IrConstructor)
irClass.declarations[index] = transformEnumConstructor(declaration)
}
}
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
for (parameter in enumConstructor.valueParameters) {
val defaultValue = parameter.defaultValue ?: continue
defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
defaultValue.patchDeclarationParents(loweredEnumConstructor)
}
return loweredEnumConstructor
}
private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl {
val startOffset = constructor.startOffset
val endOffset = constructor.endOffset
val loweredConstructor = WrappedClassConstructorDescriptor(
constructor.descriptor.annotations,
constructor.descriptor.source
).let {
IrConstructorImpl(
startOffset, endOffset,
constructor.origin,
IrConstructorSymbolImpl(it),
constructor.name,
Visibilities.PROTECTED,
constructor.returnType,
isInline = false,
isExternal = false,
isPrimary = constructor.isPrimary
).apply {
it.bind(this)
parent = constructor.parent
body = constructor.body!! // Will be transformed later.
}
}
fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) =
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(it),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
it.bind(this)
parent = loweredConstructor
}
}
loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType)
loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType)
constructor.valueParameters.mapTo(loweredConstructor.valueParameters) {
it.copyTo(loweredConstructor, index = it.loweredIndex).apply {
loweredEnumConstructorParameters[it] = this
}
}
loweredEnumConstructors[constructor] = loweredConstructor
return loweredConstructor
}
private fun lowerEnumClassBody(defaultClass: IrClass?) {
irClass.transformChildrenVoid(EnumClassBodyTransformer(defaultClass))
// Enum entries's classes have already been pulled out to the upper level - clear them up.
irClass.declarations.filterIsInstance<IrEnumEntry>().forEach { it.correspondingClass = null }
}
private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) :
EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
enumConstructorCall.symbol)
assert(result.symbol.owner.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}"
}
val nameParameter = enumClassConstructor.valueParameters.getOrElse(0) {
throw AssertionError("No 'name' parameter in enum constructor: $enumClassConstructor")
}
val ordinalParameter = enumClassConstructor.valueParameters.getOrElse(1) {
throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor")
}
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin)
)
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin)
)
return result
}
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
val startOffset = delegatingConstructorCall.startOffset
val endOffset = delegatingConstructorCall.endOffset
val delegatingConstructor = delegatingConstructorCall.symbol.owner
val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor")
}
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
loweredDelegatingConstructor.symbol)
val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, firstParameter.type, firstParameter.symbol))
val secondParameter = enumClassConstructor.valueParameters[1]
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
delegatingConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index))
}
return result
}
}
private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor)
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val enumConstructor = enumConstructorCall.symbol.owner
val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor")
}
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
result.putValueArgument(0,
IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name))
result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
enumConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index))
}
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: IrConstructorSymbol): IrMemberAccessExpression
}
private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(
startOffset: Int,
endOffset: Int,
loweredConstructor: IrConstructorSymbol
) = IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor
)
}
private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.owner]?.symbol
?: loweredConstructor
return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol)
}
}
private inner class EnumClassBodyTransformer(val defaultClass: IrClass?) : IrElementTransformerVoid() {
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.kind == ClassKind.ENUM_CLASS || declaration == defaultClass)
return declaration
return super.visitClass(declaration)
}
override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryInitializer(declaration)
declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null)
enumConstructorCallTransformer = null
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
val containingClass = declaration.parentAsClass
// TODO local (non-enum) class in enum class constructor?
val previous = enumConstructorCallTransformer
if (containingClass.kind == ClassKind.ENUM_ENTRY) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
val entry = irClass.declarations.filterIsInstance<IrEnumEntry>().single { it.correspondingClass == containingClass }
enumConstructorCallTransformer = InEnumEntryClassConstructor(entry)
} else if (containingClass.kind == ClassKind.ENUM_CLASS) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumClassConstructor(declaration)
}
val result = super.visitConstructor(declaration)
enumConstructorCallTransformer = previous
return result
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression)
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.symbol.owner.parentAsClass.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 visitGetValue(expression: IrGetValue): IrExpression {
val parameter = expression.symbol.owner
val loweredParameter = loweredEnumConstructorParameters[parameter]
return if (loweredParameter == null) {
expression
} else {
IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type,
loweredParameter.symbol, expression.origin)
}
}
}
}
}
private val IrValueParameter.loweredIndex: Int get() = index + 2
private class ParameterMapper(superConstructor: IrConstructor,
val constructor: IrConstructor,
val useLoweredIndex: Boolean) : IrElementTransformerVoid() {
private val valueParameters = superConstructor.valueParameters.toSet()
override fun visitGetValue(expression: IrGetValue): IrExpression {
val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression
if (valueParameters.contains(superParameter)) {
val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index
val parameter = constructor.valueParameters[index]
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
parameter.type,
parameter.symbol)
}
return expression
}
}
@@ -0,0 +1,389 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.descriptors.ClassKind
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.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
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.name.Name
internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPass {
fun run(irFile: IrFile) {
runOnFilePostfix(irFile)
}
override fun lower(irClass: IrClass) {
if (irClass.kind != ClassKind.ENUM_CLASS) return
EnumClassTransformer(irClass).run()
}
private interface EnumConstructorCallTransformer {
fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression
fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression
}
private inner class EnumClassTransformer(val irClass: IrClass) {
private val loweredEnumConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val loweredEnumConstructorParameters = mutableMapOf<IrValueParameter, IrValueParameter>()
fun run() {
insertInstanceInitializerCall()
lowerEnumConstructors(irClass)
lowerEnumEntriesClasses()
lowerEnumClassBody()
}
private fun insertInstanceInitializerCall() {
irClass.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// Skip nested
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
declaration.transformChildrenVoid(this)
val blockBody = declaration.body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
if (blockBody.statements.all { it !is IrInstanceInitializerCall }) {
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.symbol, context.irBuiltIns.unitType))
else null
}
}
return declaration
}
})
}
private fun lowerEnumEntriesClasses() {
for (enumEntry in irClass.declarations.filterIsInstance<IrEnumEntry>())
enumEntry.correspondingClass?.let { lowerEnumConstructors(it) }
}
private fun lowerEnumConstructors(irClass: IrClass) {
irClass.declarations.forEachIndexed { index, declaration ->
if (declaration is IrConstructor)
irClass.declarations[index] = transformEnumConstructor(declaration)
}
}
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
for (parameter in enumConstructor.valueParameters) {
val defaultValue = parameter.defaultValue ?: continue
defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
defaultValue.patchDeclarationParents(loweredEnumConstructor)
}
return loweredEnumConstructor
}
private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl {
val startOffset = constructor.startOffset
val endOffset = constructor.endOffset
val loweredConstructor = WrappedClassConstructorDescriptor(
constructor.descriptor.annotations,
constructor.descriptor.source
).let {
IrConstructorImpl(
startOffset, endOffset,
constructor.origin,
IrConstructorSymbolImpl(it),
constructor.name,
Visibilities.PROTECTED,
constructor.returnType,
isInline = false,
isExternal = false,
isPrimary = constructor.isPrimary
).apply {
it.bind(this)
parent = constructor.parent
body = constructor.body!! // Will be transformed later.
}
}
fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) =
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(it),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
it.bind(this)
parent = loweredConstructor
}
}
loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType)
loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType)
constructor.valueParameters.mapTo(loweredConstructor.valueParameters) {
it.copyTo(loweredConstructor, index = it.loweredIndex).apply {
loweredEnumConstructorParameters[it] = this
}
}
loweredEnumConstructors[constructor] = loweredConstructor
return loweredConstructor
}
private fun lowerEnumClassBody() {
val transformer = EnumClassBodyTransformer()
irClass.transformChildrenVoid(transformer)
irClass.declarations.filterIsInstance<IrEnumEntry>().forEach {
it.correspondingClass?.transformChildrenVoid(transformer)
}
}
private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) :
EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
enumConstructorCall.symbol)
assert(result.symbol.owner.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}"
}
val nameParameter = enumClassConstructor.valueParameters.getOrElse(0) {
throw AssertionError("No 'name' parameter in enum constructor: $enumClassConstructor")
}
val ordinalParameter = enumClassConstructor.valueParameters.getOrElse(1) {
throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor")
}
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin)
)
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin)
)
return result
}
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
val startOffset = delegatingConstructorCall.startOffset
val endOffset = delegatingConstructorCall.endOffset
val delegatingConstructor = delegatingConstructorCall.symbol.owner
val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor")
}
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
loweredDelegatingConstructor.symbol)
val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, firstParameter.type, firstParameter.symbol))
val secondParameter = enumClassConstructor.valueParameters[1]
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
delegatingConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index))
}
return result
}
}
private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor)
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val enumConstructor = enumConstructorCall.symbol.owner
val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor")
}
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
result.putValueArgument(0,
IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name))
result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
enumConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index))
}
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: IrConstructorSymbol): IrMemberAccessExpression
}
private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(
startOffset: Int,
endOffset: Int,
loweredConstructor: IrConstructorSymbol
) = IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor
)
}
private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) =
IrCallImpl(startOffset, endOffset, loweredConstructor.owner.returnType, loweredConstructor)
}
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() {
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.kind == ClassKind.ENUM_CLASS)
return declaration
return super.visitClass(declaration)
}
override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryInitializer(declaration)
declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null)
enumConstructorCallTransformer = null
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
val containingClass = declaration.parentAsClass
// TODO local (non-enum) class in enum class constructor?
val previous = enumConstructorCallTransformer
if (containingClass.kind == ClassKind.ENUM_ENTRY) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
val entry = irClass.declarations.filterIsInstance<IrEnumEntry>().single { it.correspondingClass == containingClass }
enumConstructorCallTransformer = InEnumEntryClassConstructor(entry)
} else if (containingClass.kind == ClassKind.ENUM_CLASS) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumClassConstructor(declaration)
}
val result = super.visitConstructor(declaration)
enumConstructorCallTransformer = previous
return result
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression)
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.symbol.owner.parentAsClass.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 visitGetValue(expression: IrGetValue): IrExpression {
val parameter = expression.symbol.owner
val loweredParameter = loweredEnumConstructorParameters[parameter]
return if (loweredParameter == null) {
expression
} else {
IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type,
loweredParameter.symbol, expression.origin)
}
}
}
}
}
private val IrValueParameter.loweredIndex: Int get() = index + 2
private class ParameterMapper(superConstructor: IrConstructor,
val constructor: IrConstructor,
val useLoweredIndex: Boolean) : IrElementTransformerVoid() {
private val valueParameters = superConstructor.valueParameters.toSet()
override fun visitGetValue(expression: IrGetValue): IrExpression {
val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression
if (valueParameters.contains(superParameter)) {
val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index
val parameter = constructor.valueParameters[index]
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
parameter.type,
parameter.symbol)
}
return expression
}
}
@@ -488,7 +488,7 @@ internal object DataFlowIR {
}, data = null)
}
private fun IrClass.isFinal() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
private fun IrClass.isFinal() = modality == Modality.FINAL
fun mapClassReferenceType(irClass: IrClass, eraseLocalObjects: Boolean = true): Type {
// Do not try to devirtualize ObjC classes.