Rewrote enum lowering to support usage from other modules.
- Split up enum lowering into two stages: descriptors creation and IR creation. - Added link stage test. - Enum.valueOf() uses binary search instead of linear.
This commit is contained in:
+9
@@ -22,8 +22,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import java.lang.System.out
|
||||
|
||||
internal class SpecialDescriptorsFactory(val context: Context) {
|
||||
private val enumSpecialDescriptorsFactory by lazy { EnumSpecialDescriptorsFactory(context) }
|
||||
private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>()
|
||||
private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, FunctionDescriptor>()
|
||||
private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>()
|
||||
|
||||
fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor =
|
||||
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor")
|
||||
@@ -54,6 +56,13 @@ internal class SpecialDescriptorsFactory(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
|
||||
assert(enumClassDescriptor.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: $enumClassDescriptor" })
|
||||
return loweredEnums.getOrPut(enumClassDescriptor) {
|
||||
enumSpecialDescriptorsFactory.createLoweredEnum(enumClassDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl,
|
||||
descriptor: FunctionDescriptor,
|
||||
bridgeDirections: Array<BridgeDirection>) {
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
internal data class LoweredEnum(val implObjectDescriptor: ClassDescriptor,
|
||||
val valuesProperty: PropertyDescriptor,
|
||||
val valuesGetter: FunctionDescriptor,
|
||||
val valuesFunction: FunctionDescriptor,
|
||||
val valueOfFunction: FunctionDescriptor,
|
||||
val itemGetter: FunctionDescriptor,
|
||||
val entriesMap: Map<Name, Int>)
|
||||
|
||||
internal class EnumSpecialDescriptorsFactory(val context: Context) {
|
||||
fun createLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
|
||||
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL,
|
||||
ClassKind.OBJECT, KonanPlatform.builtIns.anyType.singletonList(), SourceElement.NO_SOURCE, false)
|
||||
|
||||
val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor)
|
||||
val valuesFunction = createValuesFunctionDescriptor(enumClassDescriptor, implObjectDescriptor)
|
||||
val valueOfFunction = createValueOfFunctionDescriptor(enumClassDescriptor, implObjectDescriptor)
|
||||
val valuesGetter = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
|
||||
|
||||
val memberScope = MemberScope.Empty
|
||||
|
||||
val constructorOfAny = context.builtIns.any.constructors.first()
|
||||
val constructorDescriptor = implObjectDescriptor.createSimpleDelegatingConstructorDescriptor(constructorOfAny)
|
||||
|
||||
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
|
||||
|
||||
return LoweredEnum(implObjectDescriptor, valuesProperty, valuesGetter, valuesFunction, valueOfFunction,
|
||||
getEnumItemGetter(enumClassDescriptor), createEnumEntriesMap(enumClassDescriptor))
|
||||
}
|
||||
|
||||
private fun createValuesFunctionDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
|
||||
: FunctionDescriptor {
|
||||
val returnType = genericArrayType.defaultType.replace(listOf(TypeProjectionImpl(enumClassDescriptor.defaultType)))
|
||||
val result = SimpleFunctionDescriptorImpl.create(
|
||||
/* containingDeclaration = */ implObjectDescriptor,
|
||||
/* annotations = */ Annotations.EMPTY,
|
||||
/* name = */ "values".synthesizedName,
|
||||
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
/* source = */ SourceElement.NO_SOURCE)
|
||||
result.initialize(
|
||||
/* receiverParameterType = */ null,
|
||||
/* dispatchReceiverParameter = */ null,
|
||||
/* typeParameters = */ listOf(),
|
||||
/* unsubstitutedValueParameters = */ listOf(),
|
||||
/* unsubstitutedReturnType = */ returnType,
|
||||
/* modality = */ Modality.FINAL,
|
||||
/* visibility = */ Visibilities.PUBLIC)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createValuesGetterDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
|
||||
: FunctionDescriptor {
|
||||
val returnType = genericArrayType.defaultType.replace(listOf(TypeProjectionImpl(enumClassDescriptor.defaultType)))
|
||||
val result = SimpleFunctionDescriptorImpl.create(
|
||||
/* containingDeclaration = */ implObjectDescriptor,
|
||||
/* annotations = */ Annotations.EMPTY,
|
||||
/* name = */ "get-VALUES".synthesizedName,
|
||||
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
/* source = */ SourceElement.NO_SOURCE)
|
||||
result.initialize(
|
||||
/* receiverParameterType = */ null,
|
||||
/* dispatchReceiverParameter = */ null,
|
||||
/* typeParameters = */ listOf(),
|
||||
/* unsubstitutedValueParameters = */ listOf(),
|
||||
/* unsubstitutedReturnType = */ returnType,
|
||||
/* modality = */ Modality.FINAL,
|
||||
/* visibility = */ Visibilities.PUBLIC)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createValueOfFunctionDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
|
||||
: FunctionDescriptor {
|
||||
val result = SimpleFunctionDescriptorImpl.create(
|
||||
/* containingDeclaration = */ implObjectDescriptor,
|
||||
/* annotations = */ Annotations.EMPTY,
|
||||
/* name = */ "valueOf".synthesizedName,
|
||||
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
/* source = */ SourceElement.NO_SOURCE)
|
||||
val nameParameterDescriptor = ValueParameterDescriptorImpl(
|
||||
containingDeclaration = result,
|
||||
original = null,
|
||||
index = 0,
|
||||
annotations = Annotations.EMPTY,
|
||||
name = Name.identifier("name"),
|
||||
outType = context.builtIns.stringType,
|
||||
declaresDefaultValue = false,
|
||||
isCrossinline = false,
|
||||
isNoinline = false,
|
||||
varargElementType = null,
|
||||
source = SourceElement.NO_SOURCE)
|
||||
result.initialize(
|
||||
/* receiverParameterType = */ null,
|
||||
/* dispatchReceiverParameter = */ null,
|
||||
/* typeParameters = */ listOf(),
|
||||
/* unsubstitutedValueParameters = */ listOf(nameParameterDescriptor),
|
||||
/* unsubstitutedReturnType = */ enumClassDescriptor.defaultType,
|
||||
/* modality = */ Modality.FINAL,
|
||||
/* visibility = */ Visibilities.PUBLIC)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createEnumValuesField(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor): PropertyDescriptor {
|
||||
val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, enumClassDescriptor.defaultType)
|
||||
val receiver = ReceiverParameterDescriptorImpl(implObjectDescriptor, ImplicitClassReceiver(implObjectDescriptor))
|
||||
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC,
|
||||
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
|
||||
false, false, false, false, false, false).initialize(valuesArrayType, dispatchReceiverParameter = receiver)
|
||||
}
|
||||
|
||||
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
||||
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): FunctionDescriptor {
|
||||
val getter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND).single()
|
||||
|
||||
val typeParameterT = genericArrayType.declaredTypeParameters[0]
|
||||
val enumClassType = enumClassDescriptor.defaultType
|
||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
|
||||
return getter.substitute(typeSubstitutor)!!
|
||||
}
|
||||
|
||||
private fun createEnumEntriesMap(enumClassDescriptor: ClassDescriptor): Map<Name, Int> {
|
||||
val map = mutableMapOf<Name, Int>()
|
||||
enumClassDescriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
||||
.filter { it is ClassDescriptor && it.kind == ClassKind.ENUM_ENTRY }
|
||||
.sortedBy { it.name }
|
||||
.forEachIndexed { index, entry -> map.put(entry.name, index) }
|
||||
return map
|
||||
}
|
||||
|
||||
}
|
||||
+9
-6
@@ -28,8 +28,8 @@ fun ir2stringWhole(ir: IrElement?): String {
|
||||
return strWriter.toString()
|
||||
}
|
||||
|
||||
internal fun ClassDescriptor.createSimpleDelegatingConstructor(superConstructorDescriptor: ClassConstructorDescriptor)
|
||||
: Pair<ClassConstructorDescriptor, IrConstructor> {
|
||||
internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor)
|
||||
: ClassConstructorDescriptor {
|
||||
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
|
||||
this,
|
||||
Annotations.EMPTY,
|
||||
@@ -40,20 +40,23 @@ internal fun ClassDescriptor.createSimpleDelegatingConstructor(superConstructorD
|
||||
}
|
||||
constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
|
||||
constructorDescriptor.returnType = superConstructorDescriptor.returnType
|
||||
return constructorDescriptor
|
||||
}
|
||||
|
||||
internal fun ClassDescriptor.createSimpleDelegatingConstructor(superConstructorDescriptor: ClassConstructorDescriptor,
|
||||
constructorDescriptor: ClassConstructorDescriptor)
|
||||
: IrConstructor {
|
||||
val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
listOf(
|
||||
IrDelegatingConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, superConstructorDescriptor).apply {
|
||||
valueParameters.forEachIndexed { idx, parameter ->
|
||||
constructorDescriptor.valueParameters.forEachIndexed { idx, parameter ->
|
||||
putValueArgument(idx, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter))
|
||||
}
|
||||
},
|
||||
IrInstanceInitializerCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this)
|
||||
)
|
||||
)
|
||||
val constructor = IrConstructorImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, constructorDescriptor, body)
|
||||
|
||||
return Pair(constructorDescriptor, constructor)
|
||||
return IrConstructorImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, constructorDescriptor, body)
|
||||
}
|
||||
|
||||
internal fun Context.createArrayOfExpression(arrayElementType: KotlinType,
|
||||
|
||||
+69
-128
@@ -5,20 +5,15 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.ir.createArrayOfExpression
|
||||
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructor
|
||||
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -30,26 +25,14 @@ import org.jetbrains.kotlin.ir.util.transform
|
||||
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.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
|
||||
// TODO: cross-module usage.
|
||||
|
||||
internal data class LoweredSyntheticFunction(val functionDescriptor: FunctionDescriptor, val containingClass: ClassDescriptor)
|
||||
|
||||
internal data class LoweredEnumEntry(val implObject: ClassDescriptor, val valuesProperty: PropertyDescriptor,
|
||||
val itemGetter: FunctionDescriptor, val entriesMap: Map<Name, Int>)
|
||||
|
||||
internal class EnumUsageLowering(val context: Context,
|
||||
val loweredFunctions: Map<FunctionDescriptor, LoweredSyntheticFunction>,
|
||||
val loweredEnumEntries: Map<ClassDescriptor, LoweredEnumEntry>)
|
||||
internal class EnumUsageLowering(val context: Context)
|
||||
: IrElementTransformerVoid(), FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
@@ -58,54 +41,53 @@ internal class EnumUsageLowering(val context: Context,
|
||||
|
||||
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
|
||||
val enumClassDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
|
||||
enumClassDescriptor.companionObjectDescriptor
|
||||
return loadEnumEntry(expression.startOffset, expression.endOffset, enumClassDescriptor, expression.descriptor.name)
|
||||
}
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
if(expression.descriptor.kind != ClassKind.ENUM_ENTRY)
|
||||
if (expression.descriptor.kind != ClassKind.ENUM_ENTRY)
|
||||
return super.visitGetObjectValue(expression)
|
||||
val enumClassDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
|
||||
return loadEnumEntry(expression.startOffset, expression.endOffset, enumClassDescriptor, expression.descriptor.name)
|
||||
}
|
||||
|
||||
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClassDescriptor: ClassDescriptor, name: Name): IrExpression {
|
||||
val loweredEnumEntry = loweredEnumEntries[enumClassDescriptor]!!
|
||||
val implObject = loweredEnumEntry.implObject
|
||||
val implObjectGetter = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, implObject.classValueType!!, implObject)
|
||||
val valuesGetter = IrGetFieldImpl(startOffset, endOffset, loweredEnumEntry.valuesProperty).apply {
|
||||
receiver = implObjectGetter
|
||||
}
|
||||
val ordinal = loweredEnumEntry.entriesMap[name]!!
|
||||
return IrCallImpl(startOffset, endOffset, loweredEnumEntry.itemGetter).apply {
|
||||
dispatchReceiver = valuesGetter
|
||||
val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(enumClassDescriptor)
|
||||
val ordinal = loweredEnum.entriesMap[name]!!
|
||||
return IrCallImpl(startOffset, endOffset, loweredEnum.itemGetter).apply {
|
||||
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter)
|
||||
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, enumClassDescriptor.module.builtIns.intType, ordinal))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val loweredFunction = loweredFunctions[expression.descriptor] ?: return super.visitCall(expression)
|
||||
return IrCallImpl(expression.startOffset, expression.endOffset, loweredFunction.functionDescriptor).apply {
|
||||
val containingClass = loweredFunction.containingClass
|
||||
dispatchReceiver = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, containingClass.classValueType!!, containingClass)
|
||||
expression.transformChildrenVoid(this)
|
||||
val functionDescriptor = expression.descriptor as? FunctionDescriptor
|
||||
if (functionDescriptor == null) return expression
|
||||
if (functionDescriptor.kind != CallableMemberDescriptor.Kind.SYNTHESIZED) return expression
|
||||
val classDescriptor = functionDescriptor.containingDeclaration as? ClassDescriptor
|
||||
if (classDescriptor == null || classDescriptor.kind != ClassKind.ENUM_CLASS) return expression
|
||||
val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(classDescriptor)
|
||||
val loweredFunction = when (functionDescriptor.name.asString()) {
|
||||
"values" -> loweredEnum.valuesFunction
|
||||
"valueOf" -> loweredEnum.valueOfFunction
|
||||
else -> throw AssertionError("Unexpected synthetic enum function: $functionDescriptor")
|
||||
}
|
||||
return IrCallImpl(expression.startOffset, expression.endOffset, loweredFunction).apply {
|
||||
expression.descriptor.valueParameters.forEach { p -> putValueArgument(p, expression.getValueArgument(p)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
val loweredFunctions = mutableMapOf<FunctionDescriptor, LoweredSyntheticFunction>()
|
||||
val loweredEnumEntries = mutableMapOf<ClassDescriptor, LoweredEnumEntry>()
|
||||
|
||||
fun run(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile)
|
||||
EnumUsageLowering(context, loweredFunctions, loweredEnumEntries).lower(irFile)
|
||||
EnumUsageLowering(context).lower(irFile)
|
||||
}
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val descriptor = irClass.descriptor
|
||||
if (descriptor.kind != ClassKind.ENUM_CLASS)
|
||||
return
|
||||
if (descriptor.kind != ClassKind.ENUM_CLASS) return
|
||||
EnumClassTransformer(irClass).run()
|
||||
}
|
||||
|
||||
@@ -115,16 +97,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
|
||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
||||
private val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(irClass.descriptor)
|
||||
private val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>()
|
||||
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, ClassConstructorDescriptor>()
|
||||
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
|
||||
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, ClassConstructorDescriptor>()
|
||||
private val loweredEnumConstructorParameters = mutableMapOf<ValueParameterDescriptor, ValueParameterDescriptor>()
|
||||
|
||||
private lateinit var valuesFieldDescriptor: PropertyDescriptor
|
||||
private lateinit var valuesFunctionDescriptor: FunctionDescriptor
|
||||
private lateinit var valueOfFunctionDescriptor: FunctionDescriptor
|
||||
|
||||
fun run() {
|
||||
insertInstanceInitializerCall()
|
||||
assignOrdinalsToEnumEntries()
|
||||
@@ -196,7 +175,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
|
||||
descriptor.constructors.forEach {
|
||||
val loweredEnumConstructor = loweredEnumConstructors[it]!!
|
||||
val (constructorDescriptor, constructor) = defaultClassDescriptor.createSimpleDelegatingConstructor(loweredEnumConstructor)
|
||||
val constructorDescriptor = defaultClassDescriptor.createSimpleDelegatingConstructorDescriptor(loweredEnumConstructor)
|
||||
val constructor = defaultClassDescriptor.createSimpleDelegatingConstructor(loweredEnumConstructor, constructorDescriptor)
|
||||
constructors.add(constructorDescriptor)
|
||||
defaultClass.declarations.add(constructor)
|
||||
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
|
||||
@@ -219,9 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
|
||||
private fun createImplObject() {
|
||||
val descriptor = irClass.descriptor
|
||||
val implObjectDescriptor = ClassDescriptorImpl(descriptor, "OBJECT".synthesizedName, Modality.FINAL,
|
||||
ClassKind.OBJECT, KonanPlatform.builtIns.anyType.singletonList(), SourceElement.NO_SOURCE, false)
|
||||
val implObjectDescriptor = loweredEnum.implObjectDescriptor
|
||||
val implObject = IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, implObjectDescriptor)
|
||||
|
||||
val enumEntries = mutableListOf<IrEnumEntry>()
|
||||
@@ -235,18 +213,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
delete = true
|
||||
}
|
||||
is IrFunction -> {
|
||||
var copiedDescriptor = tryCopySyntheticBodyDeclaration(implObjectDescriptor, declaration, IrSyntheticBodyKind.ENUM_VALUES)
|
||||
if(copiedDescriptor != null)
|
||||
{
|
||||
valuesFunctionDescriptor = copiedDescriptor
|
||||
if (declaration.body is IrSyntheticBody)
|
||||
delete = true
|
||||
}
|
||||
copiedDescriptor = tryCopySyntheticBodyDeclaration(implObjectDescriptor, declaration, IrSyntheticBodyKind.ENUM_VALUEOF)
|
||||
if(copiedDescriptor != null)
|
||||
{
|
||||
valueOfFunctionDescriptor = copiedDescriptor
|
||||
delete = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (delete)
|
||||
@@ -255,76 +223,47 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
++i
|
||||
}
|
||||
|
||||
val memberScope = MemberScope.Empty
|
||||
|
||||
val constructorOfAny = irClass.descriptor.module.builtIns.any.constructors.first()
|
||||
val (constructorDescriptor, constructor) = implObjectDescriptor.createSimpleDelegatingConstructor(constructorOfAny)
|
||||
|
||||
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
|
||||
val constructor = implObjectDescriptor.createSimpleDelegatingConstructor(constructorOfAny, implObjectDescriptor.constructors.single())
|
||||
|
||||
implObject.declarations.add(constructor)
|
||||
implObject.declarations.add(createSyntheticValuesFieldDeclaration(implObjectDescriptor, enumEntries))
|
||||
implObject.declarations.add(createSyntheticValuesMethodDeclaration(implObjectDescriptor))
|
||||
implObject.declarations.add(createSyntheticValueOfMethodDeclaration(implObjectDescriptor))
|
||||
implObject.declarations.add(createSyntheticValuesPropertyDeclaration(enumEntries))
|
||||
implObject.declarations.add(createSyntheticValuesMethodDeclaration())
|
||||
implObject.declarations.add(createSyntheticValueOfMethodDeclaration())
|
||||
|
||||
irClass.declarations.add(implObject)
|
||||
}
|
||||
|
||||
private fun tryCopySyntheticBodyDeclaration(implObjectDescriptor: ClassDescriptor,
|
||||
declaration: IrFunction,
|
||||
kind: IrSyntheticBodyKind): FunctionDescriptor? {
|
||||
if (!declaration.body.let { it is IrSyntheticBody && it.kind == kind })
|
||||
return null
|
||||
val newDescriptor = declaration.descriptor
|
||||
.newCopyBuilder()
|
||||
.setOwner(implObjectDescriptor)
|
||||
.setName(declaration.descriptor.name.identifier.synthesizedName)
|
||||
.setDispatchReceiverParameter(implObjectDescriptor.thisAsReceiverParameter)
|
||||
.build()!!
|
||||
loweredFunctions.put(declaration.descriptor, LoweredSyntheticFunction(newDescriptor, implObjectDescriptor))
|
||||
return newDescriptor
|
||||
}
|
||||
private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrPropertyImpl {
|
||||
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType,
|
||||
enumEntries.sortedBy { it.descriptor.name }.map { it.initializerExpression })
|
||||
|
||||
private fun createSyntheticValuesFieldDeclaration(implObjectDescriptor: ClassDescriptor,
|
||||
enumEntries: List<IrEnumEntry>): IrFieldImpl {
|
||||
val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, irClass.descriptor.defaultType)
|
||||
valuesFieldDescriptor = createSyntheticValuesFieldDescriptor(implObjectDescriptor, valuesArrayType)
|
||||
|
||||
val getter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND).single()
|
||||
|
||||
val typeParameterT = genericArrayType.declaredTypeParameters[0]
|
||||
val enumClassType = irClass.descriptor.defaultType
|
||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
|
||||
val substitutedValueOf = getter.substitute(typeSubstitutor)!!
|
||||
|
||||
val entriesMap = enumEntries.associateBy({ it -> it.descriptor.name }, { it -> enumEntryOrdinals[it.descriptor]!! }).toMap()
|
||||
val loweredEnumEntry = LoweredEnumEntry(implObjectDescriptor, valuesFieldDescriptor, substitutedValueOf, entriesMap)
|
||||
loweredEnumEntries.put(irClass.descriptor, loweredEnumEntry)
|
||||
|
||||
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType, enumEntries.map { it.initializerExpression })
|
||||
|
||||
val irField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED,
|
||||
valuesFieldDescriptor,
|
||||
val irField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_ENUM,
|
||||
loweredEnum.valuesProperty,
|
||||
IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irValuesInitializer))
|
||||
return irField
|
||||
|
||||
val getter = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_ENUM, loweredEnum.valuesGetter)
|
||||
|
||||
val receiver = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
|
||||
val value = IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valuesProperty, receiver)
|
||||
val returnStatement = IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
loweredEnum.valuesGetter.returnType!!, loweredEnum.valuesGetter, value)
|
||||
getter.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(returnStatement))
|
||||
|
||||
val irProperty = IrPropertyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_ENUM,
|
||||
false, loweredEnum.valuesProperty, irField, getter, null)
|
||||
return irProperty
|
||||
}
|
||||
|
||||
private fun createSyntheticValuesFieldDescriptor(implObjectDescriptor: ClassDescriptor, valuesArrayType: SimpleType): PropertyDescriptorImpl {
|
||||
val receiver = ReceiverParameterDescriptorImpl(implObjectDescriptor, ImplicitClassReceiver(implObjectDescriptor))
|
||||
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
|
||||
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, irClass.descriptor.source,
|
||||
false, false, false, false, false, false).initialize(valuesArrayType, dispatchReceiverParameter = receiver)
|
||||
}
|
||||
|
||||
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
||||
private object DECLARATION_ORIGIN_ENUM :
|
||||
IrDeclarationOriginImpl("ENUM")
|
||||
|
||||
private val genericValueOfFun = context.builtIns.getKonanInternalFunctions("valueOfForEnum").single()
|
||||
|
||||
private val genericValuesFun = context.builtIns.getKonanInternalFunctions("valuesForEnum").single()
|
||||
|
||||
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
private fun createSyntheticValuesMethodDeclaration(companionObjectDescriptor: ClassDescriptor): IrFunction {
|
||||
private fun createSyntheticValuesMethodDeclaration(): IrFunction {
|
||||
val typeParameterT = genericValuesFun.typeParameters[0]
|
||||
val enumClassType = irClass.descriptor.defaultType
|
||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
|
||||
@@ -332,18 +271,19 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
|
||||
val irValuesCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, substitutedValueOf, mapOf(typeParameterT to enumClassType))
|
||||
.apply {
|
||||
val receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, companionObjectDescriptor.thisAsReceiverParameter)
|
||||
putValueArgument(0, IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesFieldDescriptor, receiver))
|
||||
val receiver = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
|
||||
putValueArgument(0, IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valuesProperty, receiver))
|
||||
}
|
||||
|
||||
val body = IrBlockBodyImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesFunctionDescriptor, irValuesCall))
|
||||
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valuesFunction, irValuesCall))
|
||||
)
|
||||
return IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, valuesFunctionDescriptor, body)
|
||||
return IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_ENUM, loweredEnum.valuesFunction, body)
|
||||
}
|
||||
|
||||
private fun createSyntheticValueOfMethodDeclaration(companionObjectDescriptor: ClassDescriptor): IrFunction {
|
||||
private fun createSyntheticValueOfMethodDeclaration(): IrFunction {
|
||||
val typeParameterT = genericValueOfFun.typeParameters[0]
|
||||
val enumClassType = irClass.descriptor.defaultType
|
||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
|
||||
@@ -351,16 +291,17 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
|
||||
val irValueOfCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, substitutedValueOf, mapOf(typeParameterT to enumClassType))
|
||||
.apply {
|
||||
putValueArgument(0, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueOfFunctionDescriptor.valueParameters[0]))
|
||||
val receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, companionObjectDescriptor.thisAsReceiverParameter)
|
||||
putValueArgument(1, IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesFieldDescriptor, receiver))
|
||||
putValueArgument(0, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valueOfFunction.valueParameters[0]))
|
||||
val receiver = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
|
||||
putValueArgument(1, IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valuesProperty, receiver))
|
||||
}
|
||||
|
||||
val body = IrBlockBodyImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueOfFunctionDescriptor, irValueOfCall))
|
||||
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, loweredEnum.valueOfFunction, irValueOfCall))
|
||||
)
|
||||
return IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, valueOfFunctionDescriptor, body)
|
||||
return IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_ENUM, loweredEnum.valueOfFunction, body)
|
||||
}
|
||||
|
||||
private fun lowerEnumConstructors(irClass: IrClass) {
|
||||
@@ -595,12 +536,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2
|
||||
private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2
|
||||
|
||||
private class ParameterMapper(val originalDescriptor:FunctionDescriptor): IrElementTransformerVoid() {
|
||||
private class ParameterMapper(val originalDescriptor: FunctionDescriptor) : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val descriptor = expression.descriptor
|
||||
when(descriptor) {
|
||||
when (descriptor) {
|
||||
is ValueParameterDescriptor -> {
|
||||
return IrGetValueImpl(expression.startOffset,
|
||||
expression.endOffset,
|
||||
|
||||
@@ -349,12 +349,12 @@ task enum1(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task enum_valueOf(type: RunKonanTest) {
|
||||
goldValue = "E1\n"
|
||||
goldValue = "E1\nE2\nE3\n"
|
||||
source = "codegen/enum/valueOf.kt"
|
||||
}
|
||||
|
||||
task enum_values(type: RunKonanTest) {
|
||||
goldValue = "E2\n"
|
||||
goldValue = "E3\nE1\nE2\n"
|
||||
source = "codegen/enum/values.kt"
|
||||
}
|
||||
|
||||
@@ -383,6 +383,12 @@ task enum_interfaceCallWithEntryClass(type: RunKonanTest) {
|
||||
source = "codegen/enum/interfaceCallWithEntryClass.kt"
|
||||
}
|
||||
|
||||
task enum_linkTest(type: LinkKonanTest) {
|
||||
goldValue = "42\n117\n-1\n"
|
||||
source = "codegen/enum/linkTest_main.kt"
|
||||
lib = "codegen/enum/linkTest_lib.kt"
|
||||
}
|
||||
|
||||
task innerClass_simple(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/innerClass/simple.kt"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package a
|
||||
|
||||
enum class A(val x: Int) {
|
||||
Z1(42),
|
||||
Z2(117),
|
||||
Z3(-1)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import a.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(A.Z1.x)
|
||||
println(A.valueOf("Z2").x)
|
||||
println(A.values()[2].x)
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
enum class E {
|
||||
E3,
|
||||
E1,
|
||||
E2
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(E.valueOf("E1").toString())
|
||||
println(E.valueOf("E2").toString())
|
||||
println(E.valueOf("E3").toString())
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
enum class E {
|
||||
E3,
|
||||
E1,
|
||||
E2
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(E.values()[0].toString())
|
||||
println(E.values()[1].toString())
|
||||
println(E.values()[2].toString())
|
||||
}
|
||||
@@ -27,15 +27,26 @@ fun ThrowNoWhenBranchMatchedException(): Nothing {
|
||||
@ExportForCppRuntime
|
||||
internal fun TheEmptyString() = ""
|
||||
|
||||
fun <T: Enum<T>> valueOfForEnum(name: String, arr: Array<T>) : T
|
||||
fun <T: Enum<T>> valueOfForEnum(name: String, values: Array<T>) : T
|
||||
{
|
||||
for (x in arr)
|
||||
if (x.name == name)
|
||||
return x
|
||||
var left = 0
|
||||
var right = values.size - 1
|
||||
while (left <= right) {
|
||||
val middle = (left + right) / 2
|
||||
val x = values[middle].name.compareTo(name)
|
||||
when {
|
||||
x < 0 -> left = middle + 1
|
||||
x > 0 -> right = middle - 1
|
||||
else -> return values[middle]
|
||||
}
|
||||
}
|
||||
throw Exception("Invalid enum name: $name")
|
||||
}
|
||||
|
||||
fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T>
|
||||
{
|
||||
return values.clone() as Array<T>
|
||||
val result = Array<T?>(values.size, { null })
|
||||
for (value in values)
|
||||
result[value.ordinal] = value
|
||||
return result as Array<T>
|
||||
}
|
||||
Reference in New Issue
Block a user