[K/N][IR] Refactored enums lowering
This commit is contained in:
+4
-4
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.konan.lower.BridgesSupport
|
|||||||
import org.jetbrains.kotlin.backend.konan.lower.EnumsSupport
|
import org.jetbrains.kotlin.backend.konan.lower.EnumsSupport
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.InlineFunctionsSupport
|
import org.jetbrains.kotlin.backend.konan.lower.InlineFunctionsSupport
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.InnerClassesSupport
|
import org.jetbrains.kotlin.backend.konan.lower.InnerClassesSupport
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.InternalLoweredEnum
|
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||||
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
|
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
|
||||||
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
|
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
|
||||||
@@ -60,11 +59,12 @@ internal class NativeMapping : DefaultMapping() {
|
|||||||
data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections)
|
data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections)
|
||||||
|
|
||||||
val outerThisFields = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
val outerThisFields = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
||||||
|
val enumImplObjects = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrClass>()
|
||||||
|
val enumValueGetters = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrFunction>()
|
||||||
|
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
|
||||||
val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
|
val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
|
||||||
val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
||||||
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||||
val internalLoweredEnums = mutableMapOf<IrClass, InternalLoweredEnum>()
|
|
||||||
val externalLoweredEnums = mutableMapOf<IrClass, ExternalLoweredEnum>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||||
@@ -104,7 +104,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
val innerClassesSupport by lazy { InnerClassesSupport(mapping, irFactory) }
|
val innerClassesSupport by lazy { InnerClassesSupport(mapping, irFactory) }
|
||||||
val bridgesSupport by lazy { BridgesSupport(mapping, irBuiltIns, irFactory) }
|
val bridgesSupport by lazy { BridgesSupport(mapping, irBuiltIns, irFactory) }
|
||||||
val inlineFunctionsSupport by lazy { InlineFunctionsSupport(mapping) }
|
val inlineFunctionsSupport by lazy { InlineFunctionsSupport(mapping) }
|
||||||
val enumsSupport by lazy { EnumsSupport(this) }
|
val enumsSupport by lazy { EnumsSupport(mapping, ir.symbols, irBuiltIns, irFactory) }
|
||||||
|
|
||||||
open class LazyMember<T>(val initializer: Context.() -> T) {
|
open class LazyMember<T>(val initializer: Context.() -> T) {
|
||||||
operator fun getValue(thisRef: Context, property: KProperty<*>): T = thisRef.getValue(this)
|
operator fun getValue(thisRef: Context, property: KProperty<*>): T = thisRef.getValue(this)
|
||||||
|
|||||||
+35
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.CacheInfoBuilder
|
import org.jetbrains.kotlin.backend.konan.lower.CacheInfoBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_ENUM
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
|
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
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.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
@@ -427,6 +429,21 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase(
|
|||||||
}
|
}
|
||||||
context.internalAbi.declare(function, declaration.module)
|
context.internalAbi.declare(function, declaration.module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (declaration.isEnumClass) {
|
||||||
|
val function = context.irFactory.buildFun {
|
||||||
|
name = InternalAbi.getEnumValuesAccessorName(declaration)
|
||||||
|
returnType = context.ir.symbols.array.typeWith(declaration.defaultType)
|
||||||
|
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
||||||
|
}
|
||||||
|
|
||||||
|
context.createIrBuilder(function.symbol).run {
|
||||||
|
function.body = irBlockBody {
|
||||||
|
+irReturn(with(context.enumsSupport) { irGetValuesField(declaration) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.internalAbi.declare(function, declaration.module)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitProperty(declaration: IrProperty) {
|
override fun visitProperty(declaration: IrProperty) {
|
||||||
@@ -470,6 +487,7 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
|
|||||||
val companionObjectAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
val companionObjectAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||||
val outerThisAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
val outerThisAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||||
val lateinitPropertyAccessors = mutableMapOf<IrProperty, IrSimpleFunction>()
|
val lateinitPropertyAccessors = mutableMapOf<IrProperty, IrSimpleFunction>()
|
||||||
|
val enumValuesAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||||
|
|
||||||
val transformer = object : IrElementTransformerVoid() {
|
val transformer = object : IrElementTransformerVoid() {
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||||
@@ -561,6 +579,23 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
field.origin == DECLARATION_ORIGIN_ENUM -> {
|
||||||
|
val enumClass = irClass?.parentClassOrNull
|
||||||
|
require(enumClass != null) { "Unexpected usage of enum VALUES field" }
|
||||||
|
require(enumClass.isEnumClass) { "Expected a enum class: ${enumClass.render()}" }
|
||||||
|
val accessor = enumValuesAccessors.getOrPut(enumClass) {
|
||||||
|
context.irFactory.buildFun {
|
||||||
|
name = InternalAbi.getEnumValuesAccessorName(enumClass)
|
||||||
|
returnType = context.ir.symbols.array.typeWith(enumClass.defaultType)
|
||||||
|
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
||||||
|
isExternal = true
|
||||||
|
}.also {
|
||||||
|
context.internalAbi.reference(it, enumClass.module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IrCallImpl(expression.startOffset, expression.endOffset, expression.type, accessor.symbol, accessor.typeParameters.size, accessor.valueParameters.size)
|
||||||
|
}
|
||||||
|
|
||||||
else -> expression
|
else -> expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-12
@@ -1366,19 +1366,10 @@ internal abstract class FunctionGenerationContext(
|
|||||||
*/
|
*/
|
||||||
fun getEnumEntry(enumEntry: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
fun getEnumEntry(enumEntry: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||||
val enumClass = enumEntry.parentAsClass
|
val enumClass = enumEntry.parentAsClass
|
||||||
val loweredEnum = context.enumsSupport.getLoweredEnum(enumClass)
|
val getterId = context.enumsSupport.enumEntriesMap(enumClass)[enumEntry.name]!!.getterId
|
||||||
|
|
||||||
val getterId = loweredEnum.entriesMap[enumEntry.name]!!.getterId
|
|
||||||
val values = call(
|
|
||||||
loweredEnum.valuesGetter.llvmFunction.llvmValue,
|
|
||||||
emptyList(),
|
|
||||||
Lifetime.ARGUMENT,
|
|
||||||
exceptionHandler
|
|
||||||
)
|
|
||||||
|
|
||||||
return call(
|
return call(
|
||||||
loweredEnum.itemGetterSymbol.owner.llvmFunction.llvmValue,
|
context.enumsSupport.getValueGetter(enumClass).llvmFunction.llvmValue,
|
||||||
listOf(values, Int32(getterId).llvm),
|
listOf(Int32(getterId).llvm),
|
||||||
Lifetime.GLOBAL,
|
Lifetime.GLOBAL,
|
||||||
exceptionHandler
|
exceptionHandler
|
||||||
)
|
)
|
||||||
|
|||||||
+112
-176
@@ -18,53 +18,27 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import org.jetbrains.kotlin.ir.IrStatement
|
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.IrPropertyImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
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.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPropertySymbolImpl
|
|
||||||
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.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
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
|
||||||
|
|
||||||
private class EnumSyntheticFunctionsBuilder(val context: Context) {
|
|
||||||
fun IrBuilderWithScope.enumValues(enumClass: IrClass): IrExpression {
|
|
||||||
val loweredEnum = this@EnumSyntheticFunctionsBuilder.context.enumsSupport.getLoweredEnum(enumClass)
|
|
||||||
return irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
|
||||||
putValueArgument(0, loweredEnum.getValuesField(startOffset, endOffset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.enumValueOf(enumClass: IrClass, value: IrExpression): IrExpression {
|
|
||||||
val loweredEnum = this@EnumSyntheticFunctionsBuilder.context.enumsSupport.getLoweredEnum(enumClass)
|
|
||||||
return irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply {
|
|
||||||
putValueArgument(0, value)
|
|
||||||
putValueArgument(1, loweredEnum.getValuesField(startOffset, endOffset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val genericValueOfSymbol = context.ir.symbols.valueOfForEnum
|
|
||||||
|
|
||||||
private val genericValuesSymbol = context.ir.symbols.valuesForEnum
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class NativeEnumWhenLowering constructor(context: Context) : EnumWhenLowering(context) {
|
internal class NativeEnumWhenLowering constructor(context: Context) : EnumWhenLowering(context) {
|
||||||
override fun mapConstEnumEntry(entry: IrEnumEntry): Int {
|
override fun mapConstEnumEntry(entry: IrEnumEntry): Int {
|
||||||
val parent = entry.parentAsClass
|
val enumEntriesMap = (context as Context).enumsSupport.enumEntriesMap(entry.parentAsClass)
|
||||||
val loweredEnum = (context as Context).enumsSupport.getLoweredEnumOrNull(parent)
|
return enumEntriesMap[entry.name]!!.ordinal
|
||||||
?: return super.mapConstEnumEntry(entry)
|
|
||||||
return loweredEnum.entriesMap[entry.name]!!.ordinal
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class EnumUsageLowering(val context: Context)
|
internal class EnumUsageLowering(val context: Context) : IrElementTransformer<IrBuilderWithScope?>, FileLoweringPass {
|
||||||
: IrElementTransformer<IrBuilderWithScope?>, FileLoweringPass {
|
private val enumsSupport = context.enumsSupport
|
||||||
|
private val symbols = context.ir.symbols
|
||||||
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
|
private val arrayGet = symbols.arrayGet[symbols.array]!!
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
visitFile(irFile, data = null)
|
visitFile(irFile, data = null)
|
||||||
@@ -99,25 +73,28 @@ internal class EnumUsageLowering(val context: Context)
|
|||||||
|
|
||||||
require(irClass.kind == ClassKind.ENUM_CLASS)
|
require(irClass.kind == ClassKind.ENUM_CLASS)
|
||||||
|
|
||||||
return with(enumSyntheticFunctionsBuilder) {
|
return with(enumsSupport) {
|
||||||
if (intrinsicType == IntrinsicType.ENUM_VALUES)
|
if (intrinsicType == IntrinsicType.ENUM_VALUES)
|
||||||
data.enumValues(irClass)
|
data.irEnumValues(irClass)
|
||||||
else
|
else
|
||||||
data.enumValueOf(irClass, expression.getValueArgument(0)!!)
|
data.irEnumValueOf(irClass, expression.getValueArgument(0)!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.loadEnumEntry(enumClass: IrClass, name: Name): IrExpression {
|
private fun IrBuilderWithScope.loadEnumEntry(enumClass: IrClass, name: Name) =
|
||||||
val loweredEnum = this@EnumUsageLowering.context.enumsSupport.getLoweredEnum(enumClass)
|
irCall(arrayGet, enumClass.defaultType).apply {
|
||||||
val getterId = loweredEnum.entriesMap.getValue(name).getterId
|
dispatchReceiver = with(enumsSupport) { irGetValuesField(enumClass) }
|
||||||
return irCall(loweredEnum.itemGetterSymbol, enumClass.defaultType).apply {
|
putValueArgument(0, irInt(enumsSupport.enumEntriesMap(enumClass).getValue(name).getterId))
|
||||||
dispatchReceiver = irCall(loweredEnum.valuesGetter)
|
}
|
||||||
putValueArgument(0, irInt(getterId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
||||||
|
private val enumsSupport = context.enumsSupport
|
||||||
|
private val symbols = context.ir.symbols
|
||||||
|
private val createUninitializedInstance = symbols.createUninitializedInstance
|
||||||
|
private val initInstance = symbols.initInstance
|
||||||
|
private val arrayGet = symbols.arrayGet[symbols.array]!!
|
||||||
|
private val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
@@ -131,167 +108,137 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
private inner class EnumClassTransformer(val irClass: IrClass) {
|
||||||
private val loweredEnum = context.enumsSupport.getInternalLoweredEnum(irClass)
|
private val implObject = enumsSupport.getImplObject(irClass)
|
||||||
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
|
private val valuesField = enumsSupport.getValuesField(implObject)
|
||||||
|
private val enumEntriesMap = enumsSupport.enumEntriesMap(irClass)
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
pullUpEnumEntriesClasses()
|
val enumEntries = transformEnumBody()
|
||||||
createImplObject()
|
defineImplObject(enumEntries)
|
||||||
|
defineValueGetter()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pullUpEnumEntriesClasses() {
|
private fun transformEnumBody(): List<IrEnumEntry> {
|
||||||
irClass.declarations.transformFlat { declaration ->
|
|
||||||
if (declaration is IrEnumEntry) {
|
|
||||||
val correspondingClass = declaration.correspondingClass
|
|
||||||
declaration.correspondingClass = null
|
|
||||||
listOfNotNull(declaration, correspondingClass)
|
|
||||||
} else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createImplObject() {
|
|
||||||
val implObject = loweredEnum.implObject
|
|
||||||
|
|
||||||
val enumEntries = mutableListOf<IrEnumEntry>()
|
val enumEntries = mutableListOf<IrEnumEntry>()
|
||||||
var i = 0
|
irClass.declarations.transformFlat { declaration ->
|
||||||
while (i < irClass.declarations.size) {
|
|
||||||
val declaration = irClass.declarations[i]
|
|
||||||
var delete = false
|
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is IrEnumEntry -> {
|
is IrEnumEntry -> {
|
||||||
enumEntries.add(declaration)
|
enumEntries.add(declaration)
|
||||||
delete = true
|
val correspondingClass = declaration.correspondingClass
|
||||||
|
declaration.correspondingClass = null
|
||||||
|
listOfNotNull(correspondingClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
is IrFunction -> {
|
is IrFunction -> {
|
||||||
val body = declaration.body
|
val body = declaration.body
|
||||||
if (body is IrSyntheticBody) {
|
if (body is IrSyntheticBody) {
|
||||||
when (body.kind) {
|
declaration.body = when (body.kind) {
|
||||||
IrSyntheticBodyKind.ENUM_VALUEOF ->
|
IrSyntheticBodyKind.ENUM_VALUEOF -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) {
|
||||||
declaration.body = createSyntheticValueOfMethodBody(declaration)
|
+irReturn(with(enumsSupport) { irEnumValueOf(irClass, irGet(declaration.valueParameters[0])) })
|
||||||
IrSyntheticBodyKind.ENUM_VALUES ->
|
}
|
||||||
declaration.body = createSyntheticValuesMethodBody(declaration)
|
|
||||||
|
IrSyntheticBodyKind.ENUM_VALUES -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) {
|
||||||
|
+irReturn(with(enumsSupport) { irEnumValues(irClass) })
|
||||||
|
}
|
||||||
|
|
||||||
IrSyntheticBodyKind.ENUM_ENTRIES -> TODO("KT-48872 is not yet supported")
|
IrSyntheticBodyKind.ENUM_ENTRIES -> TODO("KT-48872 is not yet supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
if (delete)
|
|
||||||
irClass.declarations.removeAt(i)
|
|
||||||
else
|
|
||||||
++i
|
|
||||||
}
|
}
|
||||||
|
return enumEntries
|
||||||
|
}
|
||||||
|
|
||||||
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
|
private fun defineValueGetter() {
|
||||||
|
val valueGetter = enumsSupport.getValueGetter(irClass)
|
||||||
|
context.createIrBuilder(valueGetter.symbol).run {
|
||||||
|
valueGetter.body = irBlockBody(valueGetter) {
|
||||||
|
+irReturn(irCall(arrayGet, irClass.defaultType).apply {
|
||||||
|
dispatchReceiver = with(enumsSupport) { irGetValuesField(irClass) }
|
||||||
|
putValueArgument(0, irGet(valueGetter.valueParameters[0]))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
irClass.declarations.add(valueGetter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun defineImplObject(enumEntries: List<IrEnumEntry>) {
|
||||||
|
implObject.createParameterDeclarations()
|
||||||
|
|
||||||
|
implObject.addSimpleDelegatingConstructor(constructorOfAny, context.irBuiltIns, true /* TODO: why primary? */)
|
||||||
|
implObject.addFakeOverrides(context.typeSystem)
|
||||||
|
irClass.declarations.add(implObject)
|
||||||
|
|
||||||
|
ImplConstructorBuilder(implObject.constructors.single()).build(enumEntries)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ImplConstructorBuilder(val constructor: IrConstructor) {
|
||||||
|
private val irBuilder = context.createIrBuilder(constructor.symbol, constructor.startOffset, constructor.endOffset)
|
||||||
|
|
||||||
|
fun build(enumEntries: List<IrEnumEntry>) {
|
||||||
|
val statements = (constructor.body as IrBlockBody).statements
|
||||||
|
|
||||||
val companion = irClass.companionObject()
|
|
||||||
if (companion != null) {
|
|
||||||
// The initialization order is the following:
|
// The initialization order is the following:
|
||||||
// - first all enum entries in their declaration order
|
// - first all enum entries in their declaration order
|
||||||
// - then companion object if it exists
|
// - then companion object if it exists
|
||||||
val constructor = implObject.constructors.single()
|
statements += buildValuesFieldInitializer(enumEntries)
|
||||||
context.createIrBuilder(constructor.symbol).run {
|
// Split allocation and constructors calling because enum entries can reference one another.
|
||||||
(constructor.body as IrBlockBody).statements += irGetObject(companion.symbol)
|
statements += callEnumEntriesConstructors(enumEntries)
|
||||||
}
|
|
||||||
|
irClass.companionObject()?.let { statements += irBuilder.irGetObject(it.symbol) }
|
||||||
}
|
}
|
||||||
|
|
||||||
irClass.declarations += implObject
|
private fun IrBlockBuilder.irInitInstanceCall(instance: IrCall, constructor: IrConstructorCall): IrCall =
|
||||||
}
|
irCall(initInstance).apply {
|
||||||
|
|
||||||
private val createUninitializedInstance = context.ir.symbols.createUninitializedInstance.owner
|
|
||||||
|
|
||||||
private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrProperty {
|
|
||||||
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,
|
|
||||||
enumEntries
|
|
||||||
.sortedBy { it.name }
|
|
||||||
.map {
|
|
||||||
val initializer = it.initializerExpression?.expression
|
|
||||||
val entryConstructorCall = when {
|
|
||||||
initializer is IrConstructorCall -> initializer
|
|
||||||
|
|
||||||
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
|
|
||||||
initializer.statements.last() as IrConstructorCall
|
|
||||||
|
|
||||||
else -> error("Unexpected initializer: $initializer")
|
|
||||||
}
|
|
||||||
val entryClass = entryConstructorCall.symbol.owner.constructedClass
|
|
||||||
|
|
||||||
irCall(startOffset, endOffset,
|
|
||||||
createUninitializedInstance,
|
|
||||||
listOf(entryClass.defaultType)
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
|
||||||
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)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
createValuesPropertyInitializer(enumEntries)
|
|
||||||
|
|
||||||
return with(loweredEnum.valuesField.descriptor) {
|
|
||||||
IrPropertyImpl(
|
|
||||||
startOffset, endOffset, DECLARATION_ORIGIN_ENUM, IrPropertySymbolImpl(this),
|
|
||||||
name, visibility, modality, isVar, isConst, isLateInit, isDelegated, isExternal
|
|
||||||
).apply {
|
|
||||||
this.backingField = irField
|
|
||||||
this.getter = getter
|
|
||||||
this.parent = implObject
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val initInstanceSymbol = context.ir.symbols.initInstance
|
|
||||||
|
|
||||||
private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.owner.name == Name.identifier("get") }
|
|
||||||
|
|
||||||
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
|
|
||||||
|
|
||||||
private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>) {
|
|
||||||
val startOffset = irClass.startOffset
|
|
||||||
val endOffset = irClass.endOffset
|
|
||||||
|
|
||||||
fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrConstructorCall): IrCall =
|
|
||||||
irCall(initInstanceSymbol).apply {
|
|
||||||
putValueArgument(0, instance)
|
putValueArgument(0, instance)
|
||||||
putValueArgument(1, constructor)
|
putValueArgument(1, constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
val implObject = loweredEnum.implObject
|
private fun buildValuesFieldInitializer(enumEntries: List<IrEnumEntry>) = irBuilder.run {
|
||||||
val constructor = implObject.constructors.single()
|
val irValuesInitializer = this@EnumClassLowering.context.createArrayOfExpression(
|
||||||
val irBuilder = context.createIrBuilder(constructor.symbol, startOffset, endOffset)
|
startOffset, endOffset,
|
||||||
val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) {
|
irClass.defaultType,
|
||||||
|
enumEntries
|
||||||
|
.sortedBy { it.name }
|
||||||
|
.map {
|
||||||
|
val initializer = it.initializerExpression?.expression
|
||||||
|
val entryConstructorCall = when {
|
||||||
|
initializer is IrConstructorCall -> initializer
|
||||||
|
|
||||||
|
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
|
||||||
|
initializer.statements.last() as IrConstructorCall
|
||||||
|
|
||||||
|
else -> error("Unexpected initializer: $initializer")
|
||||||
|
}
|
||||||
|
val entryClass = entryConstructorCall.symbol.owner.constructedClass
|
||||||
|
|
||||||
|
irCall(createUninitializedInstance, listOf(entryClass.defaultType))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
irSetField(irGet(implObject.thisReceiver!!), valuesField, irValuesInitializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun callEnumEntriesConstructors(enumEntries: List<IrEnumEntry>) = irBuilder.irBlock {
|
||||||
val receiver = implObject.thisReceiver!!
|
val receiver = implObject.thisReceiver!!
|
||||||
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
|
val instances = irTemporary(irGetField(irGet(receiver), valuesField))
|
||||||
val enumIndices = enumEntries.sortedBy { it.name }.withIndex().associate { it.value to it.index }
|
|
||||||
enumEntries.forEach {
|
enumEntries.forEach {
|
||||||
val instance = irCall(arrayGetSymbol).apply {
|
val instance = irCall(arrayGet).apply {
|
||||||
dispatchReceiver = irGet(instances)
|
dispatchReceiver = irGet(instances)
|
||||||
putValueArgument(0, irInt(enumIndices[it]!!))
|
putValueArgument(0, irInt(enumEntriesMap[it.name]!!.getterId))
|
||||||
}
|
}
|
||||||
val initializer = it.initializerExpression!!.expression
|
val initializer = it.initializerExpression!!.expression
|
||||||
initializer.setDeclarationsParent(constructor)
|
initializer.setDeclarationsParent(constructor)
|
||||||
when {
|
when {
|
||||||
initializer is IrConstructorCall -> +initInstanceCall(instance, initializer)
|
initializer is IrConstructorCall -> +irInitInstanceCall(instance, initializer)
|
||||||
|
|
||||||
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
|
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
|
||||||
val statements = initializer.statements
|
val statements = initializer.statements
|
||||||
val constructorCall = statements.last() as IrConstructorCall
|
val constructorCall = statements.last() as IrConstructorCall
|
||||||
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
|
statements[statements.lastIndex] = irInitInstanceCall(instance, constructorCall)
|
||||||
+initializer
|
+initializer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,22 +247,11 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
|||||||
}
|
}
|
||||||
// Needed for legacy MM targets that do not support threads.
|
// Needed for legacy MM targets that do not support threads.
|
||||||
if (this@EnumClassLowering.context.memoryModel != MemoryModel.EXPERIMENTAL) {
|
if (this@EnumClassLowering.context.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||||
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
|
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(valuesField.type)).apply {
|
||||||
extensionReceiver = irGet(receiver)
|
extensionReceiver = irGet(receiver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(constructor.body as IrBlockBody).statements += valuesInitializer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSyntheticValuesMethodBody(declaration: IrFunction) =
|
|
||||||
context.createIrBuilder(declaration.symbol, irClass.startOffset, irClass.endOffset).irBlockBody {
|
|
||||||
+irReturn(with(enumSyntheticFunctionsBuilder) { enumValues(irClass) })
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSyntheticValueOfMethodBody(declaration: IrFunction) =
|
|
||||||
context.createIrBuilder(declaration.symbol, irClass.startOffset, irClass.endOffset).irBlockBody {
|
|
||||||
+irReturn(with(enumSyntheticFunctionsBuilder) { enumValueOf(irClass, irGet(declaration.valueParameters[0])) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -228,7 +228,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
|
|||||||
|
|
||||||
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
|
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
|
||||||
val name = enumEntry.name.asString()
|
val name = enumEntry.name.asString()
|
||||||
val ordinal = context.enumsSupport.getEnumEntryOrdinal(enumEntry)
|
val ordinal = context.enumsSupport.enumEntriesMap(enumEntry.parentAsClass)[enumEntry.name]!!.ordinal
|
||||||
|
|
||||||
val startOffset = enumConstructorCall.startOffset
|
val startOffset = enumConstructorCall.startOffset
|
||||||
val endOffset = enumConstructorCall.endOffset
|
val endOffset = enumConstructorCall.endOffset
|
||||||
|
|||||||
+86
-223
@@ -5,255 +5,118 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.lower
|
package org.jetbrains.kotlin.backend.konan.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.NativeMapping
|
||||||
import org.jetbrains.kotlin.backend.konan.InternalAbi
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
|
||||||
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.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
internal class EnumsSupport(private val context: Context) {
|
internal class EnumsSupport(
|
||||||
private val enumSpecialDeclarationsFactory = EnumSpecialDeclarationsFactory(context)
|
mapping: NativeMapping,
|
||||||
private val internalLoweredEnums = context.mapping.internalLoweredEnums
|
symbols: KonanSymbols,
|
||||||
private val externalLoweredEnums = context.mapping.externalLoweredEnums
|
private val irBuiltIns: IrBuiltIns,
|
||||||
|
private val irFactory: IrFactory,
|
||||||
|
) {
|
||||||
|
private val enumImplObjects = mapping.enumImplObjects
|
||||||
|
private val enumValueGetters = mapping.enumValueGetters
|
||||||
|
private val enumEntriesMaps = mapping.enumEntriesMaps
|
||||||
|
private val array = symbols.array
|
||||||
|
private val genericValueOfSymbol = symbols.valueOfForEnum
|
||||||
|
private val genericValuesSymbol = symbols.valuesForEnum
|
||||||
|
|
||||||
fun getLoweredEnumOrNull(enumClass: IrClass): LoweredEnumAccess? {
|
fun enumEntriesMap(enumClass: IrClass): Map<Name, LoweredEnumEntryDescription> {
|
||||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||||
return if (!context.llvmModuleSpecification.containsDeclaration(enumClass)) {
|
return enumEntriesMaps.getOrPut(enumClass) {
|
||||||
externalLoweredEnums[enumClass]
|
data class NameWithOrdinal(val name: Name, val ordinal: Int)
|
||||||
} else {
|
enumClass.declarations.asSequence()
|
||||||
internalLoweredEnums[enumClass]
|
.filterIsInstance<IrEnumEntry>()
|
||||||
|
.mapIndexed { index, it -> NameWithOrdinal(it.name, index) }
|
||||||
|
.sortedBy { it.name }
|
||||||
|
.withIndex()
|
||||||
|
.associate { it.value.name to LoweredEnumEntryDescription(it.value.ordinal, it.index) }
|
||||||
|
.toMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLoweredEnum(enumClass: IrClass): LoweredEnumAccess {
|
fun getImplObject(enumClass: IrClass): IrClass {
|
||||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||||
return if (!context.llvmModuleSpecification.containsDeclaration(enumClass)) {
|
return enumImplObjects.getOrPut(enumClass) {
|
||||||
externalLoweredEnums.getOrPut(enumClass) {
|
irFactory.buildClass {
|
||||||
enumSpecialDeclarationsFactory.createExternalLoweredEnum(enumClass)
|
startOffset = enumClass.startOffset
|
||||||
}
|
endOffset = enumClass.endOffset
|
||||||
} else {
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
internalLoweredEnums.getOrPut(enumClass) {
|
name = "OBJECT".synthesizedName
|
||||||
enumSpecialDeclarationsFactory.createInternalLoweredEnum(enumClass)
|
kind = ClassKind.OBJECT
|
||||||
|
}.apply {
|
||||||
|
superTypes = listOf(irBuiltIns.anyType)
|
||||||
|
parent = enumClass
|
||||||
|
|
||||||
|
addChild(irFactory.buildField {
|
||||||
|
startOffset = enumClass.startOffset
|
||||||
|
endOffset = enumClass.endOffset
|
||||||
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
|
name = "VALUES".synthesizedName
|
||||||
|
type = array.typeWith(enumClass.defaultType)
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
isFinal = true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInternalLoweredEnum(enumClass: IrClass): InternalLoweredEnum {
|
fun getValueGetter(enumClass: IrClass): IrFunction {
|
||||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||||
require(context.llvmModuleSpecification.containsDeclaration(enumClass)) { "Expected enum class from current module." }
|
return enumValueGetters.getOrPut(enumClass) {
|
||||||
return internalLoweredEnums.getOrPut(enumClass) {
|
irFactory.buildFun {
|
||||||
enumSpecialDeclarationsFactory.createInternalLoweredEnum(enumClass)
|
startOffset = enumClass.startOffset
|
||||||
|
endOffset = enumClass.endOffset
|
||||||
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
|
name = "getEnumAt".synthesizedName
|
||||||
|
returnType = enumClass.defaultType
|
||||||
|
}.apply {
|
||||||
|
parent = enumClass
|
||||||
|
|
||||||
|
addValueParameter {
|
||||||
|
name = Name.identifier("getterId")
|
||||||
|
origin = DECLARATION_ORIGIN_ENUM
|
||||||
|
type = irBuiltIns.intType
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEnumEntryOrdinal(enumEntry: IrEnumEntry) =
|
fun getValuesField(implObject: IrClass) = implObject.fields.single()
|
||||||
enumEntry.parentAsClass.declarations.filterIsInstance<IrEnumEntry>().indexOf(enumEntry)
|
|
||||||
|
fun IrBuilderWithScope.irGetValuesField(enumClass: IrClass): IrExpression {
|
||||||
|
val implObject = getImplObject(enumClass)
|
||||||
|
val valuesField = getValuesField(implObject)
|
||||||
|
return irGetField(irGetObject(implObject.symbol), valuesField)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) =
|
||||||
|
irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
||||||
|
putValueArgument(0, irGetValuesField(enumClass))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irEnumValueOf(enumClass: IrClass, value: IrExpression) =
|
||||||
|
irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply {
|
||||||
|
putValueArgument(0, value)
|
||||||
|
putValueArgument(1, irGetValuesField(enumClass))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM")
|
internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM")
|
||||||
|
|
||||||
internal data class LoweredEnumEntryDescription(val ordinal: Int, val getterId: Int)
|
internal data class LoweredEnumEntryDescription(val ordinal: Int, val getterId: Int)
|
||||||
|
|
||||||
/**
|
|
||||||
* Common interface for both [InternalLoweredEnum] and [ExternalLoweredEnum]
|
|
||||||
* that allows to work with lowered enum regardless of its location.
|
|
||||||
*/
|
|
||||||
internal interface LoweredEnumAccess {
|
|
||||||
val valuesGetter: IrSimpleFunction
|
|
||||||
val itemGetterSymbol: IrSimpleFunctionSymbol
|
|
||||||
val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
|
||||||
fun getValuesField(startOffset: Int, endOffset: Int): IrExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents lowered enum from current module.
|
|
||||||
*/
|
|
||||||
internal data class InternalLoweredEnum(
|
|
||||||
val implObject: IrClass,
|
|
||||||
val valuesField: IrField,
|
|
||||||
val valuesGetterWrapper: IrSimpleFunction,
|
|
||||||
override val valuesGetter: IrSimpleFunction,
|
|
||||||
override val itemGetterSymbol: IrSimpleFunctionSymbol,
|
|
||||||
override val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
|
||||||
) : LoweredEnumAccess {
|
|
||||||
private fun internalObjectGetter(startOffset: Int, endOffset: Int) =
|
|
||||||
IrGetObjectValueImpl(startOffset, endOffset,
|
|
||||||
implObject.defaultType,
|
|
||||||
implObject.symbol
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun getValuesField(startOffset: Int, endOffset: Int): IrExpression = IrGetFieldImpl(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
valuesField.symbol,
|
|
||||||
valuesField.type,
|
|
||||||
internalObjectGetter(startOffset, endOffset)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents lowered enum that's located in external module.
|
|
||||||
*/
|
|
||||||
internal data class ExternalLoweredEnum(
|
|
||||||
override val valuesGetter: IrSimpleFunction,
|
|
||||||
override val itemGetterSymbol: IrSimpleFunctionSymbol,
|
|
||||||
override val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
|
||||||
) : LoweredEnumAccess {
|
|
||||||
override fun getValuesField(startOffset: Int, endOffset: Int): IrExpression =
|
|
||||||
IrCallImpl(startOffset, endOffset, valuesGetter.returnType, valuesGetter.symbol, valuesGetter.typeParameters.size, valuesGetter.valueParameters.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class EnumSpecialDeclarationsFactory(val context: Context) {
|
|
||||||
private val symbols = context.ir.symbols
|
|
||||||
|
|
||||||
private fun enumEntriesMap(enumClass: IrClass): Map<Name, LoweredEnumEntryDescription> {
|
|
||||||
data class NameWithOrdinal(val name: Name, val ordinal: Int)
|
|
||||||
return enumClass.declarations.asSequence()
|
|
||||||
.filterIsInstance<IrEnumEntry>()
|
|
||||||
.mapIndexed { index, it -> NameWithOrdinal(it.name, index) }
|
|
||||||
.sortedBy { it.name }
|
|
||||||
.withIndex()
|
|
||||||
.associate { it.value.name to LoweredEnumEntryDescription(it.value.ordinal, it.index) }
|
|
||||||
.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findItemGetterSymbol(): IrSimpleFunctionSymbol =
|
|
||||||
symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
|
|
||||||
|
|
||||||
private fun valuesArrayType(enumClass: IrClass): IrType =
|
|
||||||
symbols.array.typeWith(enumClass.defaultType)
|
|
||||||
|
|
||||||
// We can't move property getter to the top-level scope.
|
|
||||||
// So add a wrapper instead.
|
|
||||||
private fun createValuesGetterWrapper(enumClass: IrClass, isExternal: Boolean): IrSimpleFunction =
|
|
||||||
context.irFactory.buildFun {
|
|
||||||
name = InternalAbi.getEnumValuesAccessorName(enumClass)
|
|
||||||
returnType = valuesArrayType(enumClass)
|
|
||||||
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
|
||||||
this.isExternal = isExternal
|
|
||||||
}.also {
|
|
||||||
if (isExternal) {
|
|
||||||
context.internalAbi.reference(it, enumClass.module)
|
|
||||||
} else {
|
|
||||||
context.internalAbi.declare(it, enumClass.module)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createExternalLoweredEnum(enumClass: IrClass): ExternalLoweredEnum {
|
|
||||||
val enumEntriesMap = enumEntriesMap(enumClass)
|
|
||||||
val itemGetterSymbol = findItemGetterSymbol()
|
|
||||||
val valuesGetterWrapper = createValuesGetterWrapper(enumClass, isExternal = true)
|
|
||||||
return ExternalLoweredEnum(valuesGetterWrapper, itemGetterSymbol, enumEntriesMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createInternalLoweredEnum(enumClass: IrClass): InternalLoweredEnum {
|
|
||||||
val startOffset = enumClass.startOffset
|
|
||||||
val endOffset = enumClass.endOffset
|
|
||||||
|
|
||||||
val implObject =
|
|
||||||
IrClassImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
DECLARATION_ORIGIN_ENUM,
|
|
||||||
IrClassSymbolImpl(),
|
|
||||||
"OBJECT".synthesizedName,
|
|
||||||
ClassKind.OBJECT,
|
|
||||||
DescriptorVisibilities.PUBLIC,
|
|
||||||
Modality.FINAL,
|
|
||||||
isCompanion = false,
|
|
||||||
isInner = false,
|
|
||||||
isData = false,
|
|
||||||
isExternal = false,
|
|
||||||
isValue = false,
|
|
||||||
isExpect = false,
|
|
||||||
isFun = false
|
|
||||||
).apply {
|
|
||||||
parent = enumClass
|
|
||||||
createParameterDeclarations()
|
|
||||||
}
|
|
||||||
|
|
||||||
val valuesType = valuesArrayType(enumClass)
|
|
||||||
val valuesField =
|
|
||||||
IrFieldImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
DECLARATION_ORIGIN_ENUM,
|
|
||||||
IrFieldSymbolImpl(),
|
|
||||||
"VALUES".synthesizedName,
|
|
||||||
valuesType,
|
|
||||||
DescriptorVisibilities.PRIVATE,
|
|
||||||
isFinal = true,
|
|
||||||
isExternal = false,
|
|
||||||
isStatic = false,
|
|
||||||
).apply {
|
|
||||||
parent = implObject
|
|
||||||
}
|
|
||||||
|
|
||||||
val valuesGetter =
|
|
||||||
IrFunctionImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
DECLARATION_ORIGIN_ENUM,
|
|
||||||
IrSimpleFunctionSymbolImpl(),
|
|
||||||
"get-VALUES".synthesizedName,
|
|
||||||
DescriptorVisibilities.PUBLIC,
|
|
||||||
Modality.FINAL,
|
|
||||||
valuesType,
|
|
||||||
isInline = false,
|
|
||||||
isExternal = false,
|
|
||||||
isTailrec = false,
|
|
||||||
isSuspend = false,
|
|
||||||
isExpect = false,
|
|
||||||
isFakeOverride = false,
|
|
||||||
isOperator = false,
|
|
||||||
isInfix = false
|
|
||||||
).apply {
|
|
||||||
parent = implObject
|
|
||||||
}
|
|
||||||
|
|
||||||
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
|
|
||||||
implObject.addSimpleDelegatingConstructor(
|
|
||||||
constructorOfAny,
|
|
||||||
context.irBuiltIns,
|
|
||||||
true // TODO: why primary?
|
|
||||||
)
|
|
||||||
|
|
||||||
implObject.superTypes += context.irBuiltIns.anyType
|
|
||||||
implObject.addFakeOverrides(context.typeSystem)
|
|
||||||
|
|
||||||
val itemGetterSymbol = findItemGetterSymbol()
|
|
||||||
val enumEntriesMap = enumEntriesMap(enumClass)
|
|
||||||
val valuesGetterWrapper = createValuesGetterWrapper(enumClass, isExternal = false)
|
|
||||||
context.createIrBuilder(valuesGetterWrapper.symbol).run {
|
|
||||||
valuesGetterWrapper.body = irBlockBody {
|
|
||||||
+irReturn(irCall(valuesGetter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return InternalLoweredEnum(
|
|
||||||
implObject,
|
|
||||||
valuesField,
|
|
||||||
valuesGetterWrapper,
|
|
||||||
valuesGetter,
|
|
||||||
itemGetterSymbol,
|
|
||||||
enumEntriesMap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user