diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt index 32553ed9cad..9ad60ee07c2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt @@ -8,29 +8,31 @@ package org.jetbrains.kotlin.backend.jvm.lower import gnu.trove.TObjectIntHashMap import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl -import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter 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.PropertyDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.types.toIrType -import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi2ir.findSingleFunction import org.jetbrains.kotlin.types.* -import org.jetbrains.org.objectweb.asm.Opcodes import java.util.* internal val enumClassPhase = makeIrFilePhase( @@ -51,30 +53,30 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression } - private val arrayOfFun = context.ir.symbols.arrayOf.owner - private val unsubstitutedArrayOfFunDescriptor = arrayOfFun.descriptor + private fun createArrayOfExpression(arrayElementType: IrSimpleType, arrayElements: List): IrExpression { + val arrayOfFun = context.ir.symbols.arrayOf.owner - private fun createArrayOfExpression(arrayElementType: KotlinType, arrayElements: List): IrExpression { + /* Substituted descriptor is only needed to construct IrCall */ + val unsubstitutedArrayOfFunDescriptor = arrayOfFun.descriptor val typeParameter0 = unsubstitutedArrayOfFunDescriptor.typeParameters[0] - val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType))) + val typeSubstitutor = TypeSubstitutor.create( + mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType.toKotlinType())) + ) val substitutedArrayOfDescriptor = unsubstitutedArrayOfFunDescriptor.substitute(typeSubstitutor)!! - - val valueParameter0 = substitutedArrayOfDescriptor.valueParameters[0] - val arg0VarargType = valueParameter0.type - val arg0VarargElementType = valueParameter0.varargElementType!! + val arrayType = context.irBuiltIns.arrayClass.typeWith(arrayElementType) val arg0 = - IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arg0VarargType.toIrType()!!, arg0VarargElementType.toIrType()!!, arrayElements) + IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, arrayElementType, arrayElements) return IrCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - substitutedArrayOfDescriptor.returnType!!.toIrType()!!, + arrayType, arrayOfFun.symbol, substitutedArrayOfDescriptor, arrayOfFun.typeParameters.size ).apply { - putTypeArgument(0, arrayElementType.toIrType()!!) + putTypeArgument(0, arrayElementType) putValueArgument(0, arg0) } } @@ -82,8 +84,8 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP private inner class EnumClassTransformer(val irClass: IrClass) { private val enumEntryOrdinals = TObjectIntHashMap() private val enumEntryClassToEntry = HashMap() - private val loweredEnumConstructors = HashMap() - private val loweredEnumConstructorParameters = HashMap() + private val loweredEnumConstructors = HashMap() + private val loweredEnumConstructorParameters = HashMap() private val enumEntriesByField = HashMap() private val enumEntryFields = ArrayList() @@ -125,56 +127,73 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP enumConstructor: IrConstructor, enumClass: IrClass ): IrConstructor { - val constructorDescriptor = enumConstructor.descriptor - val loweredConstructorDescriptor = lowerEnumConstructor(constructorDescriptor) + val descriptor = WrappedClassConstructorDescriptor(enumConstructor.descriptor.annotations, enumConstructor.descriptor.source) return IrConstructorImpl( - enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin, - loweredConstructorDescriptor, - loweredConstructorDescriptor.returnType.toIrType()!!, - enumConstructor.body!! // will be transformed later + enumConstructor.startOffset, enumConstructor.endOffset, + enumConstructor.origin, + IrConstructorSymbolImpl(descriptor), + enumConstructor.name, + Visibilities.PROTECTED, + returnType = enumConstructor.returnType, + isInline = enumConstructor.isInline, + isExternal = enumConstructor.isExternal, + isPrimary = enumConstructor.isPrimary ).apply { + val newConstructor = this + descriptor.bind(this) parent = enumClass - createParameterDeclarations() - loweredEnumConstructors[constructorDescriptor] = this - constructorDescriptor.valueParameters.forEach { - loweredEnumConstructorParameters[it] = valueParameters[2 + it.index] - } + + val nameParameter = makeNameValueParameter(newConstructor) + val ordinalParameter = makeOrdinalValueParameter(newConstructor) + valueParameters.add(0, nameParameter) + valueParameters.add(1, ordinalParameter) + valueParameters.addAll(enumConstructor.valueParameters.map { param -> + param.copyTo(newConstructor, index = param.index + 2).also { newParam -> + loweredEnumConstructorParameters[param.symbol] = newParam + } + }) + + body = enumConstructor.body // will be transformed later + + loweredEnumConstructors[enumConstructor.symbol] = this metadata = enumConstructor.metadata } } - private fun lowerEnumConstructor(constructorDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor { - val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized( - constructorDescriptor.containingDeclaration, - constructorDescriptor.annotations, - constructorDescriptor.isPrimary, - constructorDescriptor.source - ) - - val valueParameters = - listOf( - loweredConstructorDescriptor.createValueParameter(0, "name", context.builtIns.stringType), - loweredConstructorDescriptor.createValueParameter(1, "ordinal", context.builtIns.intType) - ) + - constructorDescriptor.valueParameters.map { - lowerConstructorValueParameter(loweredConstructorDescriptor, it) - } - loweredConstructorDescriptor.initialize(valueParameters, Visibilities.PROTECTED) - - loweredConstructorDescriptor.returnType = constructorDescriptor.returnType - - return loweredConstructorDescriptor + private fun makeNameValueParameter(constructor: IrConstructor): IrValueParameter { + val descriptor = WrappedValueParameterDescriptor() + return IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + IrValueParameterSymbolImpl(descriptor), + Name.identifier("name"), + index = 0, + type = context.irBuiltIns.stringType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + descriptor.bind(this) + parent = constructor + } } - private fun lowerConstructorValueParameter( - loweredConstructorDescriptor: ClassConstructorDescriptor, - valueParameterDescriptor: ValueParameterDescriptor - ): ValueParameterDescriptor { - return valueParameterDescriptor.copy( - loweredConstructorDescriptor, - valueParameterDescriptor.name, - valueParameterDescriptor.index + 2 - ) + private fun makeOrdinalValueParameter(constructor: IrConstructor): IrValueParameter { + val descriptor = WrappedValueParameterDescriptor() + return IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + IrValueParameterSymbolImpl(descriptor), + Name.identifier("ordinal"), + index = 1, + type = context.irBuiltIns.intType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + descriptor.bind(this) + parent = constructor + } } private fun lowerEnumEntries() { @@ -224,39 +243,37 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP private fun createSyntheticValuesFieldDeclaration(): IrFieldImpl { - val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, irClass.descriptor.defaultType) + val valuesArrayType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType) val irValuesInitializer = createSyntheticValuesFieldInitializerExpression() + val descriptor = WrappedFieldDescriptor() + // TODO: mark ACC_SYNTHETIC return IrFieldImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES, - createSyntheticValuesFieldDescriptor(valuesArrayType), - valuesArrayType.toIrType()!!, - IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irValuesInitializer) + IrFieldSymbolImpl(descriptor), + Name.identifier("\$VALUES"), + valuesArrayType, + Visibilities.PRIVATE, + isFinal = true, + isExternal = false, + isStatic = true ).also { + descriptor.bind(it) it.parent = irClass + it.initializer = IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irValuesInitializer) + valuesField = it } } private fun createSyntheticValuesFieldInitializerExpression(): IrExpression = createArrayOfExpression( - irClass.defaultType.toKotlinType(), + irClass.defaultType, enumEntryFields.map { irField -> IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irField.symbol, irField.symbol.owner.type) }) - private fun createSyntheticValuesFieldDescriptor(valuesArrayType: SimpleType): PropertyDescriptorImpl { - return JvmPropertyDescriptorImpl.createStaticVal( - Name.identifier("\$VALUES"), - valuesArrayType, - irClass.descriptor, - Annotations.EMPTY, - Modality.FINAL, Visibilities.PRIVATE, Opcodes.ACC_SYNTHETIC, - irClass.descriptor.source - ) - } - private fun lowerEnumClassBody() { irClass.transformChildrenVoid(EnumClassBodyTransformer()) } @@ -277,7 +294,10 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP enumConstructorCall.typeArgumentsCount ) - assert(result.descriptor.valueParameters.size == 2) { + assert(enumConstructorCall.typeArgumentsCount == 1) { "Enum call expected:\n${result.dump()}" } + result.putTypeArgument(0, enumConstructorCall.getTypeArgument(0)) + + assert(result.symbol.owner.valueParameters.size == 2) { "Enum(String, Int) constructor call expected:\n${result.dump()}" } @@ -296,12 +316,11 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP } override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { - val descriptor = delegatingConstructorCall.descriptor val startOffset = delegatingConstructorCall.startOffset val endOffset = delegatingConstructorCall.endOffset - val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(descriptor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") + val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(delegatingConstructorCall.symbol) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered: ${delegatingConstructorCall.symbol}") } val result = IrDelegatingConstructorCallImpl( @@ -313,10 +332,12 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP loweredDelegatedConstructor.typeParameters.size ) + assert(loweredDelegatedConstructor.typeParameters.size == 0) { "Enum delegating call expected:\n${result.dump()}" } + result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, irEnumConstructor.valueParameters[0].symbol)) result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, irEnumConstructor.valueParameters[1].symbol)) - descriptor.valueParameters.forEach { valueParameter -> + delegatingConstructorCall.symbol.owner.valueParameters.forEach { valueParameter -> val i = valueParameter.index result.putValueArgument(i + 2, delegatingConstructorCall.getValueArgument(i)) } @@ -330,12 +351,11 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP val name = enumEntry.name.asString() val ordinal = enumEntryOrdinals[enumEntry] - val descriptor = enumConstructorCall.descriptor val startOffset = enumConstructorCall.startOffset val endOffset = enumConstructorCall.endOffset - val loweredConstructor = loweredEnumConstructors.getOrElse(descriptor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") + val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructorCall.symbol) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered:\n${enumConstructorCall.dump()}") } val result = createConstructorCall(startOffset, endOffset, loweredConstructor) @@ -343,7 +363,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP result.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name)) result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal)) - descriptor.valueParameters.forEach { valueParameter -> + enumConstructorCall.symbol.owner.valueParameters.forEach { valueParameter -> val i = valueParameter.index result.putValueArgument(i + 2, enumConstructorCall.getValueArgument(i)) } @@ -440,7 +460,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { expression.transformChildrenVoid(this) - if (expression.descriptor.containingDeclaration.kind == ClassKind.ENUM_CLASS) { + if (expression.symbol.owner.parentAsClass.kind == ClassKind.ENUM_CLASS) { val callTransformer = enumConstructorCallTransformer ?: throw AssertionError( "Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump() @@ -453,7 +473,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP } override fun visitGetValue(expression: IrGetValue): IrExpression { - val loweredParameter = loweredEnumConstructorParameters[expression.descriptor] + val loweredParameter = loweredEnumConstructorParameters[expression.symbol] return if (loweredParameter != null) { IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.symbol, expression.origin) } else { @@ -473,22 +493,25 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP } private fun createEnumValueOfBody(): IrBody { - val unsubstitutedValueOfDescriptor = context.irBuiltIns.enumValueOf - val valueOfSymbol = context.irBuiltIns.enumValueOfSymbol - val typeParameterT = unsubstitutedValueOfDescriptor.typeParameters[0] + val enumValueOf = context.irBuiltIns.enumValueOfFun + val returnType = irClass.defaultType + + val unsubstitutedValueOfDescriptor = enumValueOf.descriptor + val typeParameter0 = unsubstitutedValueOfDescriptor.typeParameters[0] val enumClassType = irClass.descriptor.defaultType - val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType))) + val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(enumClassType))) val substitutedValueOfDescriptor = unsubstitutedValueOfDescriptor.substitute(typeSubstitutor)!! val irValueOfCall = IrCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - substitutedValueOfDescriptor.returnType!!.toIrType()!!, - valueOfSymbol, + returnType, + enumValueOf.symbol, substitutedValueOfDescriptor, - substitutedValueOfDescriptor.typeParametersCount + enumValueOf.typeParameters.size ) + irValueOfCall.putTypeArgument(0, irClass.defaultType) irValueOfCall.putValueArgument( 0, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueOfFunction.valueParameters[0].symbol) ) @@ -499,7 +522,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP IrReturnImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - valueOfFunction.returnType, + returnType, valueOfFunction.symbol, irValueOfCall ) @@ -508,11 +531,10 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP } private fun createEnumValuesBody(valuesField: IrField): IrBody { - val cloneFunDescriptor = valuesField.type.toKotlinType().memberScope.findSingleFunction(Name.identifier("clone")).original - val cloneFun = context.ir.symbols.externalSymbolTable.referenceSimpleFunction(cloneFunDescriptor).owner + val cloneFun = context.irBuiltIns.arrayClass.owner.functions.find { it.name.asString() == "clone" }!! val irCloneValues = - IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, cloneFun.returnType, cloneFun.symbol, cloneFunDescriptor, 0).apply { + IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, cloneFun.returnType, cloneFun.symbol, cloneFun.descriptor, 0).apply { dispatchReceiver = IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesField.symbol, valuesField.symbol.owner.type) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index c6cefd3bfc4..61bac4fd117 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -286,8 +286,8 @@ val IrDeclarationContainer.properties: Sequence val IrFunction.explicitParameters: List get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters) -val IrClass.defaultType: IrType - get() = this.thisReceiver!!.type +val IrClass.defaultType: IrSimpleType + get() = this.thisReceiver!!.type as IrSimpleType val IrSimpleFunction.isReal: Boolean get() = descriptor.kind.isReal