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:
Igor Chevdar
2017-03-03 13:47:05 +03:00
parent bf65a78a93
commit 0ff306ad3a
10 changed files with 280 additions and 141 deletions
@@ -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>) {
@@ -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
}
}
@@ -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,
@@ -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,
+8 -2
View File
@@ -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>
}