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:
+5
-2
@@ -83,8 +83,8 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
|
|||||||
phaser.phase(KonanPhase.LOWER_FOR_LOOPS) {
|
phaser.phase(KonanPhase.LOWER_FOR_LOOPS) {
|
||||||
ForLoopsLowering(context).lower(irFile)
|
ForLoopsLowering(context).lower(irFile)
|
||||||
}
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
phaser.phase(KonanPhase.LOWER_ENUM_CONSTRUCTORS) {
|
||||||
EnumClassLowering(context).run(irFile)
|
EnumConstructorsLowering(context).run(irFile)
|
||||||
}
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
||||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||||
@@ -117,6 +117,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
|
|||||||
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
||||||
InnerClassLowering(context).runOnFilePostfix(irFile)
|
InnerClassLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
|
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
||||||
|
EnumClassLowering(context).run(irFile)
|
||||||
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_INTEROP_PART2) {
|
phaser.phase(KonanPhase.LOWER_INTEROP_PART2) {
|
||||||
InteropLoweringPart2(context).lower(irFile)
|
InteropLoweringPart2(context).lower(irFile)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -29,9 +29,10 @@ enum class KonanPhase(val description: String,
|
|||||||
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
|
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
|
||||||
/* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE),
|
/* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE),
|
||||||
/* ... ... */ LOWER_FOR_LOOPS("For loops lowering"),
|
/* ... ... */ 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_DELEGATION("Delegation lowering"),
|
||||||
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
|
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUM_CONSTRUCTORS),
|
||||||
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering", LOWER_INLINE),
|
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering", LOWER_INLINE),
|
||||||
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
|
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
|
||||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_DELEGATION),
|
/* ... ... */ 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_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS),
|
||||||
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
|
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
|
||||||
/* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC),
|
/* ... ... */ 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_VARARG("Vararg lowering", LOWER_CALLABLES, LOWER_DEFAULT_PARAMETER_EXTENT),
|
||||||
/* ... ... */ LOWER_COMPILE_TIME_EVAL("Compile time evaluation lowering", LOWER_VARARG, enabled = false),
|
/* ... ... */ 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),
|
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT, GEN_SYNTHETIC_FIELDS),
|
||||||
|
|||||||
-1
@@ -100,7 +100,6 @@ internal val IrClass.isInterface: Boolean
|
|||||||
get() = (this.kind == ClassKind.INTERFACE)
|
get() = (this.kind == ClassKind.INTERFACE)
|
||||||
|
|
||||||
fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
||||||
|| this.kind == ClassKind.ENUM_CLASS
|
|
||||||
|
|
||||||
internal fun IrFunction.hasValueTypeAt(index: Int): Boolean {
|
internal fun IrFunction.hasValueTypeAt(index: Int): Boolean {
|
||||||
when (index) {
|
when (index) {
|
||||||
|
|||||||
-1
@@ -134,7 +134,6 @@ internal val MemberScope.contributedMethods: List<FunctionDescriptor>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
||||||
|| this.kind == ClassKind.ENUM_CLASS
|
|
||||||
|
|
||||||
internal val FunctionDescriptor.target: FunctionDescriptor
|
internal val FunctionDescriptor.target: FunctionDescriptor
|
||||||
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
|
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
|
||||||
|
|||||||
+1
-1
@@ -131,7 +131,7 @@ val IrFunction.isOverridableOrOverrides
|
|||||||
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
|
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
|
||||||
|
|
||||||
val IrClass.isFinalClass: Boolean
|
val IrClass.isFinalClass: Boolean
|
||||||
get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
|
get() = modality == Modality.FINAL
|
||||||
|
|
||||||
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
|
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
|
||||||
if (this == other) return true
|
if (this == other) return true
|
||||||
|
|||||||
+51
-459
@@ -7,21 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
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.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
|
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.backend.konan.irasdescriptors.constructedClass
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
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.IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
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.classifierOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.typeWith
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
|
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
|
||||||
@@ -163,111 +148,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
EnumClassTransformer(irClass).run()
|
EnumClassTransformer(irClass).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface EnumConstructorCallTransformer {
|
|
||||||
fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression
|
|
||||||
fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
private inner class EnumClassTransformer(val irClass: IrClass) {
|
||||||
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(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)
|
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
insertInstanceInitializerCall()
|
pullUpEnumEntriesClasses()
|
||||||
lowerEnumConstructors(irClass)
|
|
||||||
lowerEnumEntriesClasses()
|
|
||||||
val defaultClass = createDefaultClassForEnumEntries()
|
|
||||||
lowerEnumClassBody(defaultClass)
|
|
||||||
createImplObject()
|
createImplObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertInstanceInitializerCall() {
|
private fun pullUpEnumEntriesClasses() {
|
||||||
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() {
|
|
||||||
irClass.declarations.transformFlat { declaration ->
|
irClass.declarations.transformFlat { declaration ->
|
||||||
if (declaration is IrEnumEntry) {
|
if (declaration is IrEnumEntry) {
|
||||||
listOfNotNull(declaration, lowerEnumEntryClass(declaration.correspondingClass))
|
val correspondingClass = declaration.correspondingClass
|
||||||
|
declaration.correspondingClass = null
|
||||||
|
listOfNotNull(declaration, correspondingClass)
|
||||||
} else null
|
} 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() {
|
private fun createImplObject() {
|
||||||
val implObject = loweredEnum.implObject
|
val implObject = loweredEnum.implObject
|
||||||
|
|
||||||
@@ -300,7 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
|
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
|
||||||
implObject.declarations += createValuesPropertyInitializer(enumEntries)
|
|
||||||
|
|
||||||
irClass.declarations += implObject
|
irClass.declarations += implObject
|
||||||
}
|
}
|
||||||
@@ -311,6 +210,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
val startOffset = irClass.startOffset
|
val startOffset = irClass.startOffset
|
||||||
val endOffset = irClass.endOffset
|
val endOffset = irClass.endOffset
|
||||||
|
|
||||||
|
val implObject = loweredEnum.implObject
|
||||||
|
val constructor = implObject.constructors.single()
|
||||||
|
|
||||||
val irValuesInitializer = context.createArrayOfExpression(
|
val irValuesInitializer = context.createArrayOfExpression(
|
||||||
startOffset, endOffset,
|
startOffset, endOffset,
|
||||||
irClass.defaultType,
|
irClass.defaultType,
|
||||||
@@ -335,31 +237,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val irField = loweredEnum.valuesField.apply {
|
val irField = loweredEnum.valuesField
|
||||||
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
|
context.createIrBuilder(constructor.symbol).run {
|
||||||
|
(constructor.body as IrBlockBody).statements +=
|
||||||
|
irSetField(irGet(implObject.thisReceiver!!), irField, irValuesInitializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
val getter = loweredEnum.valuesGetter
|
val getter = loweredEnum.valuesGetter
|
||||||
|
context.createIrBuilder(getter.symbol).run {
|
||||||
|
getter.body = irBlockBody(irClass) { +irReturn(irGetField(irGetObject(implObject.symbol), irField)) }
|
||||||
|
}
|
||||||
|
|
||||||
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
|
createValuesPropertyInitializer(enumEntries)
|
||||||
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))
|
|
||||||
|
|
||||||
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
|
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
|
||||||
false, loweredEnum.valuesField.descriptor, irField, getter, null).apply {
|
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 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 startOffset = irClass.startOffset
|
||||||
val endOffset = irClass.endOffset
|
val endOffset = irClass.endOffset
|
||||||
|
|
||||||
fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
|
fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
|
||||||
irCall(initInstanceSymbol).apply {
|
irCall(initInstanceSymbol).apply {
|
||||||
putValueArgument(0, instance)
|
putValueArgument(0, instance)
|
||||||
putValueArgument(1, constructor)
|
putValueArgument(1, constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
val implObject = loweredEnum.implObject
|
val implObject = loweredEnum.implObject
|
||||||
return IrAnonymousInitializerImpl(
|
val constructor = implObject.constructors.single()
|
||||||
startOffset, endOffset,
|
val irBuilder = context.createIrBuilder(constructor.symbol, startOffset, endOffset)
|
||||||
DECLARATION_ORIGIN_ENUM,
|
val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) {
|
||||||
IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor())
|
val receiver = implObject.thisReceiver!!
|
||||||
).apply {
|
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
|
||||||
parent = implObject
|
enumEntries
|
||||||
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) {
|
.sortedBy { it.name }
|
||||||
val receiver = implObject.thisReceiver!!
|
.withIndex()
|
||||||
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
|
.forEach {
|
||||||
enumEntries
|
val instance = irCall(arrayGetSymbol).apply {
|
||||||
.sortedBy { it.name }
|
dispatchReceiver = irGet(instances)
|
||||||
.withIndex()
|
putValueArgument(0, irInt(it.index))
|
||||||
.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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
|
val initializer = it.value.initializerExpression!!
|
||||||
extensionReceiver = irGet(receiver)
|
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 {
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+389
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -488,7 +488,7 @@ internal object DataFlowIR {
|
|||||||
}, data = null)
|
}, 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 {
|
fun mapClassReferenceType(irClass: IrClass, eraseLocalObjects: Boolean = true): Type {
|
||||||
// Do not try to devirtualize ObjC classes.
|
// Do not try to devirtualize ObjC classes.
|
||||||
|
|||||||
Reference in New Issue
Block a user