JVM IR: Refactor EnumClassLowering
This commit is contained in:
committed by
max-kammerer
parent
b0e61ab470
commit
1b5109b6ee
@@ -83,7 +83,7 @@ import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
|||||||
import static org.jetbrains.org.objectweb.asm.Type.getObjectType;
|
import static org.jetbrains.org.objectweb.asm.Type.getObjectType;
|
||||||
|
|
||||||
public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||||
private static final String ENUM_VALUES_FIELD_NAME = "$VALUES";
|
public static final String ENUM_VALUES_FIELD_NAME = "$VALUES";
|
||||||
private Type superClassAsmType;
|
private Type superClassAsmType;
|
||||||
@NotNull
|
@NotNull
|
||||||
private SuperClassInfo superClassInfo;
|
private SuperClassInfo superClassInfo;
|
||||||
|
|||||||
+128
-425
@@ -7,39 +7,38 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
|||||||
|
|
||||||
import gnu.trove.TObjectIntHashMap
|
import gnu.trove.TObjectIntHashMap
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.at
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.irArray
|
import org.jetbrains.kotlin.backend.jvm.ir.irArray
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||||
import org.jetbrains.kotlin.ir.builders.irExprBody
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedFieldDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
|
||||||
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.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||||
|
import org.jetbrains.kotlin.ir.util.isEnumEntry
|
||||||
|
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import java.util.*
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
internal val enumClassPhase = makeIrFilePhase(
|
internal val enumClassPhase = makeIrFilePhase(
|
||||||
::EnumClassLowering,
|
::EnumClassLowering,
|
||||||
@@ -50,460 +49,164 @@ internal val enumClassPhase = makeIrFilePhase(
|
|||||||
private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (!irClass.isEnumClass) return
|
if (!irClass.isEnumClass) return
|
||||||
|
|
||||||
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 loweredEnumConstructors = hashMapOf<IrConstructorSymbol, IrConstructorImpl>()
|
||||||
|
private val loweredEnumConstructorParameters = hashMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||||
private val enumEntryOrdinals = TObjectIntHashMap<IrEnumEntry>()
|
private val enumEntryOrdinals = TObjectIntHashMap<IrEnumEntry>()
|
||||||
private val enumEntryClassToEntry = HashMap<IrClass, IrEnumEntry>()
|
private val declarationToEnumEntry = mutableMapOf<IrDeclaration, IrEnumEntry>()
|
||||||
private val loweredEnumConstructors = HashMap<IrConstructorSymbol, IrConstructorImpl>()
|
|
||||||
private val loweredEnumConstructorParameters = HashMap<IrValueParameterSymbol, IrValueParameter>()
|
|
||||||
private val enumEntriesByField = HashMap<IrField, IrEnumEntry>()
|
|
||||||
private val enumEntryFields = ArrayList<IrField>()
|
|
||||||
|
|
||||||
private lateinit var valuesField: IrField
|
|
||||||
private lateinit var valuesFunction: IrFunction
|
|
||||||
private lateinit var valueOfFunction: IrFunction
|
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
assignOrdinalsToEnumEntries()
|
// Lower IrEnumEntry into IrField and IrClass members
|
||||||
lowerEnumConstructors(irClass)
|
irClass.declarations.asSequence().filterIsInstance<IrEnumEntry>().withIndex().forEach { (index, enumEntry) ->
|
||||||
lowerEnumEntries()
|
enumEntryOrdinals.put(enumEntry, index)
|
||||||
setupSynthesizedEnumClassMembers()
|
enumEntry.correspondingClass?.let { entryClass -> declarationToEnumEntry[entryClass] = enumEntry }
|
||||||
lowerEnumClassBody()
|
declarationToEnumEntry[buildEnumEntryField(enumEntry)] = enumEntry
|
||||||
}
|
|
||||||
|
|
||||||
private fun assignOrdinalsToEnumEntries() {
|
|
||||||
var ordinal = 0
|
|
||||||
irClass.declarations.forEach {
|
|
||||||
if (it is IrEnumEntry) {
|
|
||||||
enumEntryOrdinals.put(it, ordinal)
|
|
||||||
it.correspondingClass?.run {
|
|
||||||
enumEntryClassToEntry.put(this, it)
|
|
||||||
}
|
|
||||||
ordinal++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irClass.declarations.removeAll { it is IrEnumEntry }
|
||||||
|
irClass.declarations += declarationToEnumEntry.keys
|
||||||
|
|
||||||
|
// Construct the synthetic $VALUES field, which contains an array of all enum entries
|
||||||
|
val valuesField = buildValuesField()
|
||||||
|
|
||||||
|
// Add synthetic parameters to enum constructors and implement the values and valueOf functions
|
||||||
|
irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField))
|
||||||
|
|
||||||
|
// Add synthetic arguments to enum constructor calls and remap enum constructor paramters
|
||||||
|
irClass.transformChildrenVoid(EnumClassCallTransformer())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lowerEnumConstructors(irClass: IrClass) {
|
private fun buildEnumEntryField(enumEntry: IrEnumEntry): IrField =
|
||||||
irClass.declarations.transform { declaration ->
|
context.declarationFactory.getFieldForEnumEntry(enumEntry).apply {
|
||||||
if (declaration is IrConstructor)
|
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.patchDeclarationParents(this))
|
||||||
transformEnumConstructor(declaration, irClass)
|
annotations += enumEntry.annotations
|
||||||
else
|
|
||||||
declaration
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun transformEnumConstructor(
|
private fun buildValuesField(): IrField = irClass.addField {
|
||||||
enumConstructor: IrConstructor,
|
name = Name.identifier(ImplementationBodyCodegen.ENUM_VALUES_FIELD_NAME)
|
||||||
enumClass: IrClass
|
type = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
||||||
): IrConstructor {
|
visibility = Visibilities.PRIVATE
|
||||||
val descriptor = WrappedClassConstructorDescriptor(enumConstructor.descriptor.annotations, enumConstructor.descriptor.source)
|
origin = IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES
|
||||||
return IrConstructorImpl(
|
isFinal = true
|
||||||
enumConstructor.startOffset, enumConstructor.endOffset,
|
isStatic = true
|
||||||
enumConstructor.origin,
|
}.apply {
|
||||||
IrConstructorSymbolImpl(descriptor),
|
initializer = context.createJvmIrBuilder(symbol).run {
|
||||||
enumConstructor.name,
|
irExprBody(irArray(type) {
|
||||||
enumConstructor.visibility,
|
for (irField in declarationToEnumEntry.keys.filterIsInstance<IrField>()) {
|
||||||
returnType = enumConstructor.returnType,
|
+irGetField(null, irField)
|
||||||
isInline = enumConstructor.isInline,
|
|
||||||
isExternal = enumConstructor.isExternal,
|
|
||||||
isPrimary = enumConstructor.isPrimary,
|
|
||||||
isExpect = enumConstructor.isExpect
|
|
||||||
).apply {
|
|
||||||
val newConstructor = this
|
|
||||||
descriptor.bind(this)
|
|
||||||
parent = enumClass
|
|
||||||
|
|
||||||
val nameParameter = makeNameValueParameter(newConstructor)
|
|
||||||
val ordinalParameter = makeOrdinalValueParameter(newConstructor)
|
|
||||||
valueParameters.add(0, nameParameter)
|
|
||||||
valueParameters.add(1, ordinalParameter)
|
|
||||||
valueParameters.addAll(enumConstructor.valueParameters.map { param ->
|
|
||||||
param.copyTo(newConstructor, index = param.index + 2).also { newParam ->
|
|
||||||
loweredEnumConstructorParameters[param.symbol] = newParam
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
body = enumConstructor.body?.patchDeclarationParents(this)
|
|
||||||
|
|
||||||
loweredEnumConstructors[enumConstructor.symbol] = this
|
|
||||||
metadata = enumConstructor.metadata
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeNameValueParameter(constructor: IrConstructor): IrValueParameter {
|
private inner class EnumClassDeclarationsTransformer(val valuesField: IrField) : IrElementTransformerVoid() {
|
||||||
val descriptor = WrappedValueParameterDescriptor()
|
override fun visitClass(declaration: IrClass): IrStatement =
|
||||||
return IrValueParameterImpl(
|
if (declaration.isEnumEntry) super.visitClass(declaration) else declaration
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
|
||||||
JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER,
|
|
||||||
IrValueParameterSymbolImpl(descriptor),
|
|
||||||
Name.identifier("\$enum\$name"),
|
|
||||||
index = 0,
|
|
||||||
type = context.irBuiltIns.stringType,
|
|
||||||
varargElementType = null,
|
|
||||||
isCrossinline = false,
|
|
||||||
isNoinline = false
|
|
||||||
).apply {
|
|
||||||
descriptor.bind(this)
|
|
||||||
parent = constructor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeOrdinalValueParameter(constructor: IrConstructor): IrValueParameter {
|
override fun visitConstructor(declaration: IrConstructor): IrStatement =
|
||||||
val descriptor = WrappedValueParameterDescriptor()
|
buildConstructor {
|
||||||
return IrValueParameterImpl(
|
updateFrom(declaration)
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
returnType = declaration.returnType
|
||||||
JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER,
|
}.apply {
|
||||||
IrValueParameterSymbolImpl(descriptor),
|
parent = declaration.parent
|
||||||
Name.identifier("\$enum\$ordinal"),
|
|
||||||
index = 1,
|
|
||||||
type = context.irBuiltIns.intType,
|
|
||||||
varargElementType = null,
|
|
||||||
isCrossinline = false,
|
|
||||||
isNoinline = false
|
|
||||||
).apply {
|
|
||||||
descriptor.bind(this)
|
|
||||||
parent = constructor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lowerEnumEntries() {
|
addValueParameter(
|
||||||
irClass.transformDeclarationsFlat { declaration ->
|
"\$enum\$name", context.irBuiltIns.stringType, JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER
|
||||||
if (declaration is IrEnumEntry) {
|
|
||||||
listOfNotNull(
|
|
||||||
createFieldForEnumEntry(declaration),
|
|
||||||
lowerEnumEntryClass(declaration.correspondingClass)
|
|
||||||
)
|
)
|
||||||
} else null
|
addValueParameter(
|
||||||
}
|
"\$enum\$ordinal", context.irBuiltIns.intType, JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER
|
||||||
}
|
)
|
||||||
|
declaration.valueParameters.mapTo(valueParameters) { param ->
|
||||||
private fun lowerEnumEntryClass(enumEntryClass: IrClass?): IrClass? {
|
param.copyTo(this, index = param.index + 2).also { newParam ->
|
||||||
if (enumEntryClass == null) return null
|
loweredEnumConstructorParameters[param.symbol] = newParam
|
||||||
|
}
|
||||||
lowerEnumConstructors(enumEntryClass)
|
|
||||||
|
|
||||||
return enumEntryClass
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFieldForEnumEntry(enumEntry: IrEnumEntry): IrField =
|
|
||||||
context.declarationFactory.getFieldForEnumEntry(enumEntry).also {
|
|
||||||
it.initializer = IrExpressionBodyImpl(
|
|
||||||
enumEntry.initializerExpression!!.patchDeclarationParents(it)
|
|
||||||
)
|
|
||||||
it.annotations.addAll(enumEntry.annotations)
|
|
||||||
enumEntryFields.add(it)
|
|
||||||
enumEntriesByField[it] = enumEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupSynthesizedEnumClassMembers() {
|
|
||||||
val irField = createSyntheticValuesFieldDeclaration()
|
|
||||||
|
|
||||||
irClass.declarations.add(irField)
|
|
||||||
|
|
||||||
valuesFunction = findFunctionForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUES)
|
|
||||||
valueOfFunction = findFunctionForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUEOF)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findFunctionForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction =
|
|
||||||
irClass.declarations.asSequence().filterIsInstance<IrFunction>()
|
|
||||||
.first {
|
|
||||||
it.body.let { body ->
|
|
||||||
body is IrSyntheticBody && body.kind == kind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body = declaration.body?.patchDeclarationParents(this)
|
||||||
|
loweredEnumConstructors[declaration.symbol] = this
|
||||||
|
metadata = declaration.metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
|
||||||
|
val body = declaration.body?.safeAs<IrSyntheticBody>()
|
||||||
|
?: return declaration
|
||||||
|
|
||||||
private fun createSyntheticValuesFieldDeclaration(): IrFieldImpl {
|
declaration.body = context.createJvmIrBuilder(declaration.symbol).run {
|
||||||
val valuesArrayType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)
|
irExprBody(
|
||||||
|
when (body.kind) {
|
||||||
|
IrSyntheticBodyKind.ENUM_VALUES ->
|
||||||
|
irArray(valuesField.type) { addSpread(irGetField(null, valuesField)) }
|
||||||
|
|
||||||
val irValuesInitializer = createSyntheticValuesFieldInitializerExpression()
|
IrSyntheticBodyKind.ENUM_VALUEOF ->
|
||||||
|
irCall(backendContext.ir.symbols.enumValueOfFunction).apply {
|
||||||
val descriptor = WrappedFieldDescriptor()
|
putValueArgument(0, with(CallableReferenceLowering) {
|
||||||
return IrFieldImpl(
|
javaClassReference(irClass.defaultType, backendContext)
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES,
|
})
|
||||||
IrFieldSymbolImpl(descriptor),
|
putValueArgument(1, irGet(declaration.valueParameters[0]))
|
||||||
Name.identifier("\$VALUES"),
|
}
|
||||||
valuesArrayType,
|
}
|
||||||
Visibilities.PRIVATE,
|
)
|
||||||
isFinal = true,
|
}
|
||||||
isExternal = false,
|
return declaration
|
||||||
isStatic = true,
|
|
||||||
isFakeOverride = false
|
|
||||||
).also {
|
|
||||||
descriptor.bind(it)
|
|
||||||
it.parent = irClass
|
|
||||||
it.initializer = IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irValuesInitializer)
|
|
||||||
|
|
||||||
valuesField = it
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSyntheticValuesFieldInitializerExpression(): IrExpression =
|
private inner class EnumClassCallTransformer : IrElementTransformerVoidWithContext() {
|
||||||
context.createJvmIrBuilder(irClass.symbol).irArray(context.irBuiltIns.arrayClass.typeWith(irClass.defaultType)) {
|
override fun visitClassNew(declaration: IrClass): IrStatement =
|
||||||
enumEntryFields.forEach { irField ->
|
if (declaration.isEnumEntry) super.visitClassNew(declaration) else declaration
|
||||||
+IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irField.symbol, irField.type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lowerEnumClassBody() {
|
override fun visitGetValue(expression: IrGetValue): IrExpression =
|
||||||
irClass.transformChildrenVoid(EnumClassBodyTransformer())
|
loweredEnumConstructorParameters[expression.symbol]?.let {
|
||||||
}
|
IrGetValueImpl(expression.startOffset, expression.endOffset, it.type, it.symbol, expression.origin)
|
||||||
|
} ?: expression
|
||||||
private inner class InEnumClassConstructor(val irEnumConstructor: 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,
|
|
||||||
enumConstructorCall.typeArgumentsCount
|
|
||||||
)
|
|
||||||
|
|
||||||
assert(enumConstructorCall.typeArgumentsCount == 1) { "Enum<T> call expected:\n${result.dump()}" }
|
|
||||||
result.putTypeArgument(0, enumConstructorCall.getTypeArgument(0))
|
|
||||||
|
|
||||||
assert(result.symbol.owner.valueParameters.size == 2) {
|
|
||||||
"Enum(String, Int) constructor call expected:\n${result.dump()}"
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameParameter = irEnumConstructor.valueParameters.getOrElse(0) {
|
|
||||||
throw AssertionError("No 'name' parameter in enum constructor: ${irEnumConstructor.dump()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val ordinalParameter = irEnumConstructor.valueParameters.getOrElse(1) {
|
|
||||||
throw AssertionError("No 'ordinal' parameter in enum constructor: ${irEnumConstructor.dump()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, nameParameter.symbol, origin))
|
|
||||||
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, ordinalParameter.symbol, origin))
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
|
|
||||||
val startOffset = delegatingConstructorCall.startOffset
|
|
||||||
val endOffset = delegatingConstructorCall.endOffset
|
|
||||||
|
|
||||||
val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(delegatingConstructorCall.symbol) {
|
|
||||||
throw AssertionError("Constructor called in enum entry initializer should've been lowered: ${delegatingConstructorCall.symbol}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = IrDelegatingConstructorCallImpl(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
context.irBuiltIns.unitType,
|
|
||||||
loweredDelegatedConstructor.symbol,
|
|
||||||
loweredDelegatedConstructor.typeParameters.size
|
|
||||||
)
|
|
||||||
|
|
||||||
assert(loweredDelegatedConstructor.typeParameters.size == 0) { "Enum delegating call expected:\n${result.dump()}" }
|
|
||||||
|
|
||||||
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, irEnumConstructor.valueParameters[0].symbol))
|
|
||||||
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, irEnumConstructor.valueParameters[1].symbol))
|
|
||||||
|
|
||||||
delegatingConstructorCall.symbol.owner.valueParameters.forEach { valueParameter ->
|
|
||||||
val i = valueParameter.index
|
|
||||||
result.putValueArgument(i + 2, delegatingConstructorCall.getValueArgument(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = enumEntryOrdinals[enumEntry]
|
|
||||||
|
|
||||||
val startOffset = enumConstructorCall.startOffset
|
|
||||||
val endOffset = enumConstructorCall.endOffset
|
|
||||||
|
|
||||||
val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructorCall.symbol) {
|
|
||||||
throw AssertionError("Constructor called in enum entry initializer should've been lowered:\n${enumConstructorCall.dump()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = createConstructorCall(startOffset, endOffset, loweredConstructor)
|
|
||||||
|
|
||||||
result.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name))
|
|
||||||
result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
|
|
||||||
|
|
||||||
enumConstructorCall.symbol.owner.valueParameters.forEach { valueParameter ->
|
|
||||||
val i = valueParameter.index
|
|
||||||
result.putValueArgument(i + 2, enumConstructorCall.getValueArgument(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
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: IrConstructor
|
|
||||||
): IrMemberAccessExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
|
|
||||||
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructor) =
|
|
||||||
IrDelegatingConstructorCallImpl(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
context.irBuiltIns.unitType,
|
|
||||||
loweredConstructor.symbol,
|
|
||||||
loweredConstructor.typeParameters.size
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
|
|
||||||
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructor) =
|
|
||||||
IrConstructorCallImpl.fromSymbolDescriptor(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
loweredConstructor.symbol.owner.parentAsClass.defaultType,
|
|
||||||
loweredConstructor.symbol
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() {
|
|
||||||
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
|
|
||||||
|
|
||||||
override fun visitField(declaration: IrField): IrStatement {
|
|
||||||
val enumEntry = enumEntriesByField[declaration]
|
|
||||||
if (enumEntry == null) {
|
|
||||||
declaration.transformChildrenVoid(this)
|
|
||||||
return declaration
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
|
|
||||||
|
|
||||||
enumConstructorCallTransformer = InEnumEntryInitializer(enumEntry)
|
|
||||||
|
|
||||||
val result = super.visitField(declaration)
|
|
||||||
|
|
||||||
enumConstructorCallTransformer = null
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
|
||||||
val containingClass = declaration.parent as IrClass
|
|
||||||
|
|
||||||
// TODO local (non-enum) class in enum class constructor?
|
|
||||||
val previous = enumConstructorCallTransformer
|
|
||||||
|
|
||||||
if (containingClass.isEnumEntry) {
|
|
||||||
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
|
|
||||||
enumConstructorCallTransformer = InEnumEntryClassConstructor(enumEntryClassToEntry[containingClass]!!)
|
|
||||||
} else if (containingClass.isEnumClass) {
|
|
||||||
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 {
|
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
val scopeOwnerSymbol = currentScope!!.scope.scopeOwnerSymbol
|
||||||
|
return context.createIrBuilder(scopeOwnerSymbol).at(expression).run {
|
||||||
|
val constructor = loweredEnumConstructors[expression.symbol] ?: expression.symbol.owner
|
||||||
|
|
||||||
val callTransformer = enumConstructorCallTransformer ?: throw AssertionError(
|
if (scopeOwnerSymbol is IrConstructorSymbol) {
|
||||||
"Enum constructor call outside of enum entry initialization or enum class constructor:\n" +
|
irDelegatingConstructorCall(constructor)
|
||||||
irClass.dump()
|
} else {
|
||||||
)
|
irCall(constructor)
|
||||||
|
}.also {
|
||||||
return callTransformer.transform(expression)
|
passConstructorArguments(it, expression, declarationToEnumEntry[scopeOwnerSymbol.owner as IrDeclaration])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
val replacement = loweredEnumConstructors[expression.symbol]
|
||||||
|
?: return expression
|
||||||
|
|
||||||
if (expression.symbol.owner.parentAsClass.kind == ClassKind.ENUM_CLASS) {
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).at(expression).run {
|
||||||
val callTransformer = enumConstructorCallTransformer ?: throw AssertionError(
|
irDelegatingConstructorCall(replacement).also { passConstructorArguments(it, expression) }
|
||||||
"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 {
|
private fun IrBuilderWithScope.passConstructorArguments(
|
||||||
val loweredParameter = loweredEnumConstructorParameters[expression.symbol]
|
call: IrFunctionAccessExpression,
|
||||||
return if (loweredParameter != null) {
|
original: IrFunctionAccessExpression,
|
||||||
IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.symbol, expression.origin)
|
enumEntry: IrEnumEntry? = null
|
||||||
|
) {
|
||||||
|
call.copyTypeArgumentsFrom(original)
|
||||||
|
if (enumEntry != null) {
|
||||||
|
call.putValueArgument(0, irString(enumEntry.name.asString()))
|
||||||
|
call.putValueArgument(1, irInt(enumEntryOrdinals[enumEntry]))
|
||||||
} else {
|
} else {
|
||||||
expression
|
val constructor = currentScope!!.scope.scopeOwnerSymbol as IrConstructorSymbol
|
||||||
|
call.putValueArgument(0, irGet(constructor.owner.valueParameters[0]))
|
||||||
|
call.putValueArgument(1, irGet(constructor.owner.valueParameters[1]))
|
||||||
}
|
}
|
||||||
}
|
for (index in 0 until original.valueArgumentsCount) {
|
||||||
|
original.getValueArgument(index)?.let { call.putValueArgument(index + 2, it) }
|
||||||
override fun visitSyntheticBody(body: IrSyntheticBody): IrBody {
|
|
||||||
return when (body.kind) {
|
|
||||||
IrSyntheticBodyKind.ENUM_VALUES ->
|
|
||||||
createEnumValuesBody(valuesField)
|
|
||||||
IrSyntheticBodyKind.ENUM_VALUEOF ->
|
|
||||||
createEnumValueOfBody()
|
|
||||||
else ->
|
|
||||||
body
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createEnumValueOfBody(): IrBody =
|
|
||||||
context.createJvmIrBuilder(valueOfFunction.symbol).run {
|
|
||||||
irExprBody(
|
|
||||||
irCall(backendContext.ir.symbols.enumValueOfFunction).apply {
|
|
||||||
putValueArgument(0, with(CallableReferenceLowering) {
|
|
||||||
javaClassReference(irClass.defaultType, backendContext)
|
|
||||||
})
|
|
||||||
putValueArgument(1, irGet(valueOfFunction.valueParameters[0]))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createEnumValuesBody(valuesField: IrField): IrBody {
|
|
||||||
val cloneFun = context.irBuiltIns.arrayClass.owner.functions.find { it.name.asString() == "clone" }!!
|
|
||||||
val returnType = valuesFunction.symbol.owner.returnType
|
|
||||||
val irCloneValues =
|
|
||||||
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, returnType, cloneFun.symbol, 1).apply {
|
|
||||||
putTypeArgument(0, irClass.defaultType)
|
|
||||||
dispatchReceiver =
|
|
||||||
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesField.symbol, valuesField.symbol.owner.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
return IrBlockBodyImpl(
|
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
|
||||||
listOf(
|
|
||||||
IrReturnImpl(
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
context.irBuiltIns.nothingType,
|
|
||||||
valuesFunction.symbol,
|
|
||||||
irCloneValues
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user