From 68530bf28b7f0eafdaedcfb97b38c5f067e962d8 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Fri, 25 Jan 2019 17:29:42 +0300 Subject: [PATCH] Split up EnumClassLowering on two parts EnumConstructorsLowering will be moved to common part Also moved EnumClassLowering down along the pipeline --- .../kotlin/backend/konan/KonanLower.kt | 7 +- .../kotlin/backend/konan/KonanPhases.kt | 7 +- .../konan/descriptors/DescriptorUtils.kt | 1 - .../descriptors/LegacyDescriptorUtils.kt | 1 - .../konan/irasdescriptors/NewIrUtils.kt | 2 +- .../backend/konan/lower/EnumClassLowering.kt | 510 ++---------------- .../konan/lower/EnumConstructorsLowering.kt | 389 +++++++++++++ .../backend/konan/optimizations/DataFlowIR.kt | 2 +- 8 files changed, 451 insertions(+), 468 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumConstructorsLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 07187763752..e89f6b66f07 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -83,8 +83,8 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) phaser.phase(KonanPhase.LOWER_FOR_LOOPS) { ForLoopsLowering(context).lower(irFile) } - phaser.phase(KonanPhase.LOWER_ENUMS) { - EnumClassLowering(context).run(irFile) + phaser.phase(KonanPhase.LOWER_ENUM_CONSTRUCTORS) { + EnumConstructorsLowering(context).run(irFile) } phaser.phase(KonanPhase.LOWER_INITIALIZERS) { InitializersLowering(context).runOnFilePostfix(irFile) @@ -117,6 +117,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { InnerClassLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_ENUMS) { + EnumClassLowering(context).run(irFile) + } phaser.phase(KonanPhase.LOWER_INTEROP_PART2) { InteropLoweringPart2(context).lower(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index 77285c248f7..6a32352dac1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -29,9 +29,10 @@ enum class KonanPhase(val description: String, /* ... ... ... */ DESERIALIZER("Deserialize inline bodies"), /* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE), /* ... ... */ LOWER_FOR_LOOPS("For loops lowering"), - /* ... ... */ LOWER_ENUMS("Enum classes lowering"), + /* ... ... */ LOWER_ENUM_CONSTRUCTORS("Enum constructors lowering"), + /* ... ... */ LOWER_ENUMS("Enum classes lowering", LOWER_ENUM_CONSTRUCTORS), /* ... ... */ LOWER_DELEGATION("Delegation lowering"), - /* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS), + /* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUM_CONSTRUCTORS), /* ... ... */ LOWER_LATEINIT("Lateinit properties lowering", LOWER_INLINE), /* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS), /* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_DELEGATION), @@ -39,7 +40,7 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC), - /* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUMS), + /* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUM_CONSTRUCTORS), /* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES, LOWER_DEFAULT_PARAMETER_EXTENT), /* ... ... */ LOWER_COMPILE_TIME_EVAL("Compile time evaluation lowering", LOWER_VARARG, enabled = false), /* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT, GEN_SYNTHETIC_FIELDS), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index 3784ab5443e..682a797c270 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -100,7 +100,6 @@ internal val IrClass.isInterface: Boolean get() = (this.kind == ClassKind.INTERFACE) fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT - || this.kind == ClassKind.ENUM_CLASS internal fun IrFunction.hasValueTypeAt(index: Int): Boolean { when (index) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt index 3328b1ba46b..3e51253b17f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt @@ -134,7 +134,6 @@ internal val MemberScope.contributedMethods: List } fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT - || this.kind == ClassKind.ENUM_CLASS internal val FunctionDescriptor.target: FunctionDescriptor get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt index 0e47316e315..4132650a2f1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt @@ -131,7 +131,7 @@ val IrFunction.isOverridableOrOverrides get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty()) val IrClass.isFinalClass: Boolean - get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS + get() = modality == Modality.FINAL fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean { if (this == other) return true diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index 9b3071265c2..db074a6edca 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -7,21 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.deepCopyWithVariables -import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor -import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor -import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor -import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor -import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM -import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* @@ -29,17 +21,10 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl -import org.jetbrains.kotlin.ir.types.IrType 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.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name internal class EnumSyntheticFunctionsBuilder(val context: Context) { @@ -163,111 +148,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { EnumClassTransformer(irClass).run() } - private interface EnumConstructorCallTransformer { - fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression - fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression - } - private inner class EnumClassTransformer(val irClass: IrClass) { private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass) - private val loweredEnumConstructors = mutableMapOf() - private val defaultEnumEntryConstructors = mutableMapOf() - private val loweredEnumConstructorParameters = mutableMapOf() private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context) fun run() { - insertInstanceInitializerCall() - lowerEnumConstructors(irClass) - lowerEnumEntriesClasses() - val defaultClass = createDefaultClassForEnumEntries() - lowerEnumClassBody(defaultClass) + pullUpEnumEntriesClasses() createImplObject() } - private fun insertInstanceInitializerCall() { - irClass.transformChildrenVoid(object: IrElementTransformerVoid() { - override fun visitClass(declaration: IrClass): IrStatement { - // Skip nested - return declaration - } - - override fun visitConstructor(declaration: IrConstructor): IrStatement { - declaration.transformChildrenVoid(this) - - val blockBody = declaration.body as? IrBlockBody - ?: throw AssertionError("Unexpected constructor body: ${declaration.body}") - if (blockBody.statements.all { it !is IrInstanceInitializerCall }) { - blockBody.statements.transformFlat { - if (it is IrEnumConstructorCall) - listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset, - irClass.symbol, context.irBuiltIns.unitType)) - else null - } - } - return declaration - } - }) - } - - private fun lowerEnumEntriesClasses() { + private fun pullUpEnumEntriesClasses() { irClass.declarations.transformFlat { declaration -> if (declaration is IrEnumEntry) { - listOfNotNull(declaration, lowerEnumEntryClass(declaration.correspondingClass)) + val correspondingClass = declaration.correspondingClass + declaration.correspondingClass = null + listOfNotNull(declaration, correspondingClass) } else null } } - private fun lowerEnumEntryClass(enumEntryClass: IrClass?): IrClass? { - if (enumEntryClass == null) return null - - lowerEnumConstructors(enumEntryClass) - - return enumEntryClass - } - - private fun createDefaultClassForEnumEntries(): IrClass? { - if (!irClass.declarations.any { it is IrEnumEntry && it.correspondingClass == null }) return null - val defaultClass = WrappedClassDescriptor().let { - IrClassImpl( - irClass.startOffset, irClass.endOffset, - DECLARATION_ORIGIN_ENUM, - IrClassSymbolImpl(it), - "DEFAULT".synthesizedName, - ClassKind.CLASS, - Visibilities.PRIVATE, - Modality.FINAL, - isCompanion = false, - isInner = false, - isData = false, - isExternal = false, - isInline = false - ).apply { - it.bind(this) - parent = irClass - irClass.declarations += this - createParameterDeclarations() - } - } - - for (superConstructor in irClass.constructors) { - val constructor = defaultClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns) - defaultEnumEntryConstructors[superConstructor] = constructor - - for (parameter in constructor.valueParameters) { - val defaultValue = superConstructor.valueParameters[parameter.index].defaultValue ?: continue - val body = defaultValue.deepCopyWithVariables() - body.transformChildrenVoid(ParameterMapper(superConstructor, constructor, false)) - body.patchDeclarationParents(constructor) - parameter.defaultValue = body - } - } - - defaultClass.superTypes += irClass.defaultType - defaultClass.addFakeOverrides() - - return defaultClass - } - private fun createImplObject() { val implObject = loweredEnum.implObject @@ -300,7 +199,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries) - implObject.declarations += createValuesPropertyInitializer(enumEntries) + irClass.declarations += implObject } @@ -311,6 +210,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { 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, @@ -335,31 +237,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } ) - val irField = loweredEnum.valuesField.apply { - initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer) + 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)) } + } - val receiver = IrGetObjectValueImpl(startOffset, endOffset, - loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol) - val value = IrGetFieldImpl( - startOffset, endOffset, - loweredEnum.valuesField.symbol, - loweredEnum.valuesField.type, - receiver - ) - val returnStatement = IrReturnImpl( - startOffset, endOffset, - context.irBuiltIns.nothingType, - loweredEnum.valuesGetter.symbol, - value - ) - getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement)) + createValuesPropertyInitializer(enumEntries) return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, false, loweredEnum.valuesField.descriptor, irField, getter, null).apply { - parent = loweredEnum.implObject + parent = implObject } } @@ -369,54 +262,50 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType) - private fun createValuesPropertyInitializer(enumEntries: List): IrAnonymousInitializerImpl { + private fun createValuesPropertyInitializer(enumEntries: List) { val startOffset = irClass.startOffset val endOffset = irClass.endOffset - fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = + fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = irCall(initInstanceSymbol).apply { putValueArgument(0, instance) putValueArgument(1, constructor) } val implObject = loweredEnum.implObject - return IrAnonymousInitializerImpl( - startOffset, endOffset, - DECLARATION_ORIGIN_ENUM, - IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor()) - ).apply { - parent = implObject - body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { - val receiver = implObject.thisReceiver!! - val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField)) - enumEntries - .sortedBy { it.name } - .withIndex() - .forEach { - val instance = irCall(arrayGetSymbol).apply { - dispatchReceiver = irGet(instances) - putValueArgument(0, irInt(it.index)) - } - val initializer = it.value.initializerExpression!! - initializer.patchDeclarationParents(implObject) - when { - initializer is IrCall -> +initInstanceCall(instance, initializer) - - initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { - val statements = initializer.statements - val constructorCall = statements.last() as IrCall - statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) - +initializer - } - - else -> error("Unexpected initializer: $initializer") - } + val constructor = implObject.constructors.single() + val irBuilder = context.createIrBuilder(constructor.symbol, startOffset, endOffset) + val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) { + val receiver = implObject.thisReceiver!! + val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField)) + enumEntries + .sortedBy { it.name } + .withIndex() + .forEach { + val instance = irCall(arrayGetSymbol).apply { + dispatchReceiver = irGet(instances) + putValueArgument(0, irInt(it.index)) } - +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { - extensionReceiver = irGet(receiver) - } + val initializer = it.value.initializerExpression!! + initializer.patchDeclarationParents(constructor) + when { + initializer is IrCall -> +initInstanceCall(instance, initializer) + + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { + val statements = initializer.statements + val constructorCall = statements.last() as IrCall + statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) + +initializer + } + + else -> error("Unexpected initializer: $initializer") + } + } + +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { + extensionReceiver = irGet(receiver) } } + (constructor.body as IrBlockBody).statements += valuesInitializer } private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody { @@ -453,302 +342,5 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } } - private fun lowerEnumConstructors(irClass: IrClass) { - irClass.declarations.forEachIndexed { index, declaration -> - if (declaration is IrConstructor) - irClass.declarations[index] = transformEnumConstructor(declaration) - } - } - - private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor { - val loweredEnumConstructor = lowerEnumConstructor(enumConstructor) - - for (parameter in enumConstructor.valueParameters) { - val defaultValue = parameter.defaultValue ?: continue - defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true)) - loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue - defaultValue.patchDeclarationParents(loweredEnumConstructor) - } - - return loweredEnumConstructor - } - - private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl { - val startOffset = constructor.startOffset - val endOffset = constructor.endOffset - val loweredConstructor = WrappedClassConstructorDescriptor( - constructor.descriptor.annotations, - constructor.descriptor.source - ).let { - IrConstructorImpl( - startOffset, endOffset, - constructor.origin, - IrConstructorSymbolImpl(it), - constructor.name, - Visibilities.PROTECTED, - constructor.returnType, - isInline = false, - isExternal = false, - isPrimary = constructor.isPrimary - ).apply { - it.bind(this) - parent = constructor.parent - body = constructor.body!! // Will be transformed later. - } - } - - fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) = - WrappedValueParameterDescriptor().let { - IrValueParameterImpl( - startOffset, endOffset, - DECLARATION_ORIGIN_ENUM, - IrValueParameterSymbolImpl(it), - Name.identifier(name), - index, - type, - varargElementType = null, - isCrossinline = false, - isNoinline = false - ).apply { - it.bind(this) - parent = loweredConstructor - } - } - - loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType) - loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType) - constructor.valueParameters.mapTo(loweredConstructor.valueParameters) { - it.copyTo(loweredConstructor, index = it.loweredIndex).apply { - loweredEnumConstructorParameters[it] = this - } - } - - loweredEnumConstructors[constructor] = loweredConstructor - - return loweredConstructor - } - - private fun lowerEnumClassBody(defaultClass: IrClass?) { - irClass.transformChildrenVoid(EnumClassBodyTransformer(defaultClass)) - // Enum entries's classes have already been pulled out to the upper level - clear them up. - irClass.declarations.filterIsInstance().forEach { it.correspondingClass = null } - } - - private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) : - EnumConstructorCallTransformer { - override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { - val startOffset = enumConstructorCall.startOffset - val endOffset = enumConstructorCall.endOffset - val origin = enumConstructorCall.origin - - val result = IrDelegatingConstructorCallImpl( - startOffset, endOffset, - context.irBuiltIns.unitType, - enumConstructorCall.symbol) - - assert(result.symbol.owner.valueParameters.size == 2) { - "Enum(String, Int) constructor call expected:\n${result.dump()}" - } - - val nameParameter = enumClassConstructor.valueParameters.getOrElse(0) { - throw AssertionError("No 'name' parameter in enum constructor: $enumClassConstructor") - } - - val ordinalParameter = enumClassConstructor.valueParameters.getOrElse(1) { - throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor") - } - - result.putValueArgument(0, - IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin) - ) - result.putValueArgument(1, - IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin) - ) - return result - } - - override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { - val startOffset = delegatingConstructorCall.startOffset - val endOffset = delegatingConstructorCall.endOffset - - val delegatingConstructor = delegatingConstructorCall.symbol.owner - val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor") - } - - val result = IrDelegatingConstructorCallImpl( - startOffset, endOffset, - context.irBuiltIns.unitType, - loweredDelegatingConstructor.symbol) - - val firstParameter = enumClassConstructor.valueParameters[0] - result.putValueArgument(0, - IrGetValueImpl(startOffset, endOffset, firstParameter.type, firstParameter.symbol)) - val secondParameter = enumClassConstructor.valueParameters[1] - result.putValueArgument(1, - IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol)) - - delegatingConstructor.valueParameters.forEach { - result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index)) - } - - return result - } - } - - private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer { - - override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { - val name = enumEntry.name.asString() - val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor) - - val startOffset = enumConstructorCall.startOffset - val endOffset = enumConstructorCall.endOffset - - val enumConstructor = enumConstructorCall.symbol.owner - val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor") - } - - val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol) - - result.putValueArgument(0, - IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name)) - result.putValueArgument(1, - IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal)) - - enumConstructor.valueParameters.forEach { - result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index)) - } - - return result - } - - override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { - throw AssertionError("Unexpected delegating constructor call within enum entry: $enumEntry") - } - - abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression - } - - private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { - override fun createConstructorCall( - startOffset: Int, - endOffset: Int, - loweredConstructor: IrConstructorSymbol - ) = IrDelegatingConstructorCallImpl( - startOffset, - endOffset, - context.irBuiltIns.unitType, - loweredConstructor - ) - } - - private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { - override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall { - val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.owner]?.symbol - ?: loweredConstructor - return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol) - } - } - - private inner class EnumClassBodyTransformer(val defaultClass: IrClass?) : IrElementTransformerVoid() { - private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null - - override fun visitClass(declaration: IrClass): IrStatement { - if (declaration.kind == ClassKind.ENUM_CLASS || declaration == defaultClass) - return declaration - return super.visitClass(declaration) - } - - override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement { - assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } - - enumConstructorCallTransformer = InEnumEntryInitializer(declaration) - - declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null) - - enumConstructorCallTransformer = null - - return declaration - } - - override fun visitConstructor(declaration: IrConstructor): IrStatement { - val containingClass = declaration.parentAsClass - - // TODO local (non-enum) class in enum class constructor? - val previous = enumConstructorCallTransformer - - if (containingClass.kind == ClassKind.ENUM_ENTRY) { - assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } - val entry = irClass.declarations.filterIsInstance().single { it.correspondingClass == containingClass } - enumConstructorCallTransformer = InEnumEntryClassConstructor(entry) - } else if (containingClass.kind == ClassKind.ENUM_CLASS) { - assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } - enumConstructorCallTransformer = InEnumClassConstructor(declaration) - } - - val result = super.visitConstructor(declaration) - - enumConstructorCallTransformer = previous - - return result - } - - override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression { - expression.transformChildrenVoid(this) - - val callTransformer = enumConstructorCallTransformer ?: - throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) - - - return callTransformer.transform(expression) - } - - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { - expression.transformChildrenVoid(this) - - 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()) - - return callTransformer.transform(expression) - } - return expression - } - - override fun visitGetValue(expression: IrGetValue): IrExpression { - val parameter = expression.symbol.owner - val loweredParameter = loweredEnumConstructorParameters[parameter] - return if (loweredParameter == null) { - expression - } else { - IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type, - loweredParameter.symbol, expression.origin) - } - } - } - } -} - -private val IrValueParameter.loweredIndex: Int get() = index + 2 - -private class ParameterMapper(superConstructor: IrConstructor, - val constructor: IrConstructor, - val useLoweredIndex: Boolean) : IrElementTransformerVoid() { - private val valueParameters = superConstructor.valueParameters.toSet() - - override fun visitGetValue(expression: IrGetValue): IrExpression { - - val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression - if (valueParameters.contains(superParameter)) { - val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index - val parameter = constructor.valueParameters[index] - return IrGetValueImpl( - expression.startOffset, expression.endOffset, - parameter.type, - parameter.symbol) - } - return expression } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumConstructorsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumConstructorsLowering.kt new file mode 100644 index 00000000000..e81ddeac9f7 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumConstructorsLowering.kt @@ -0,0 +1,389 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.runOnFilePostfix +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl +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.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.patchDeclarationParents +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.Name + +internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPass { + + fun run(irFile: IrFile) { + runOnFilePostfix(irFile) + } + + override fun lower(irClass: IrClass) { + if (irClass.kind != ClassKind.ENUM_CLASS) return + EnumClassTransformer(irClass).run() + } + + private interface EnumConstructorCallTransformer { + fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression + fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression + } + + private inner class EnumClassTransformer(val irClass: IrClass) { + private val loweredEnumConstructors = mutableMapOf() + private val loweredEnumConstructorParameters = mutableMapOf() + + fun run() { + insertInstanceInitializerCall() + lowerEnumConstructors(irClass) + lowerEnumEntriesClasses() + lowerEnumClassBody() + } + + private fun insertInstanceInitializerCall() { + irClass.transformChildrenVoid(object: IrElementTransformerVoid() { + override fun visitClass(declaration: IrClass): IrStatement { + // Skip nested + return declaration + } + + override fun visitConstructor(declaration: IrConstructor): IrStatement { + declaration.transformChildrenVoid(this) + + val blockBody = declaration.body as? IrBlockBody + ?: throw AssertionError("Unexpected constructor body: ${declaration.body}") + if (blockBody.statements.all { it !is IrInstanceInitializerCall }) { + blockBody.statements.transformFlat { + if (it is IrEnumConstructorCall) + listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset, + irClass.symbol, context.irBuiltIns.unitType)) + else null + } + } + return declaration + } + }) + } + + private fun lowerEnumEntriesClasses() { + for (enumEntry in irClass.declarations.filterIsInstance()) + enumEntry.correspondingClass?.let { lowerEnumConstructors(it) } + } + + private fun lowerEnumConstructors(irClass: IrClass) { + irClass.declarations.forEachIndexed { index, declaration -> + if (declaration is IrConstructor) + irClass.declarations[index] = transformEnumConstructor(declaration) + } + } + + private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor { + val loweredEnumConstructor = lowerEnumConstructor(enumConstructor) + + for (parameter in enumConstructor.valueParameters) { + val defaultValue = parameter.defaultValue ?: continue + defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true)) + loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue + defaultValue.patchDeclarationParents(loweredEnumConstructor) + } + + return loweredEnumConstructor + } + + private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl { + val startOffset = constructor.startOffset + val endOffset = constructor.endOffset + val loweredConstructor = WrappedClassConstructorDescriptor( + constructor.descriptor.annotations, + constructor.descriptor.source + ).let { + IrConstructorImpl( + startOffset, endOffset, + constructor.origin, + IrConstructorSymbolImpl(it), + constructor.name, + Visibilities.PROTECTED, + constructor.returnType, + isInline = false, + isExternal = false, + isPrimary = constructor.isPrimary + ).apply { + it.bind(this) + parent = constructor.parent + body = constructor.body!! // Will be transformed later. + } + } + + fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) = + WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrValueParameterSymbolImpl(it), + Name.identifier(name), + index, + type, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + it.bind(this) + parent = loweredConstructor + } + } + + loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType) + loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType) + constructor.valueParameters.mapTo(loweredConstructor.valueParameters) { + it.copyTo(loweredConstructor, index = it.loweredIndex).apply { + loweredEnumConstructorParameters[it] = this + } + } + + loweredEnumConstructors[constructor] = loweredConstructor + + return loweredConstructor + } + + private fun lowerEnumClassBody() { + val transformer = EnumClassBodyTransformer() + irClass.transformChildrenVoid(transformer) + irClass.declarations.filterIsInstance().forEach { + it.correspondingClass?.transformChildrenVoid(transformer) + } + } + + private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) : + EnumConstructorCallTransformer { + override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { + val startOffset = enumConstructorCall.startOffset + val endOffset = enumConstructorCall.endOffset + val origin = enumConstructorCall.origin + + val result = IrDelegatingConstructorCallImpl( + startOffset, endOffset, + context.irBuiltIns.unitType, + enumConstructorCall.symbol) + + assert(result.symbol.owner.valueParameters.size == 2) { + "Enum(String, Int) constructor call expected:\n${result.dump()}" + } + + val nameParameter = enumClassConstructor.valueParameters.getOrElse(0) { + throw AssertionError("No 'name' parameter in enum constructor: $enumClassConstructor") + } + + val ordinalParameter = enumClassConstructor.valueParameters.getOrElse(1) { + throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor") + } + + result.putValueArgument(0, + IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin) + ) + result.putValueArgument(1, + IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin) + ) + return result + } + + override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { + val startOffset = delegatingConstructorCall.startOffset + val endOffset = delegatingConstructorCall.endOffset + + val delegatingConstructor = delegatingConstructorCall.symbol.owner + val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor") + } + + val result = IrDelegatingConstructorCallImpl( + startOffset, endOffset, + context.irBuiltIns.unitType, + loweredDelegatingConstructor.symbol) + + val firstParameter = enumClassConstructor.valueParameters[0] + result.putValueArgument(0, + IrGetValueImpl(startOffset, endOffset, firstParameter.type, firstParameter.symbol)) + val secondParameter = enumClassConstructor.valueParameters[1] + result.putValueArgument(1, + IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol)) + + delegatingConstructor.valueParameters.forEach { + result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index)) + } + + return result + } + } + + private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer { + + override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { + val name = enumEntry.name.asString() + val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor) + + val startOffset = enumConstructorCall.startOffset + val endOffset = enumConstructorCall.endOffset + + val enumConstructor = enumConstructorCall.symbol.owner + val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor") + } + + val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol) + + result.putValueArgument(0, + IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name)) + result.putValueArgument(1, + IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal)) + + enumConstructor.valueParameters.forEach { + result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index)) + } + + return result + } + + override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { + throw AssertionError("Unexpected delegating constructor call within enum entry: $enumEntry") + } + + abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression + } + + private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { + override fun createConstructorCall( + startOffset: Int, + endOffset: Int, + loweredConstructor: IrConstructorSymbol + ) = IrDelegatingConstructorCallImpl( + startOffset, + endOffset, + context.irBuiltIns.unitType, + loweredConstructor + ) + } + + private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { + override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) = + IrCallImpl(startOffset, endOffset, loweredConstructor.owner.returnType, loweredConstructor) + } + + private inner class EnumClassBodyTransformer : IrElementTransformerVoid() { + private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null + + override fun visitClass(declaration: IrClass): IrStatement { + if (declaration.kind == ClassKind.ENUM_CLASS) + return declaration + return super.visitClass(declaration) + } + + override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement { + assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } + + enumConstructorCallTransformer = InEnumEntryInitializer(declaration) + + declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null) + + enumConstructorCallTransformer = null + + return declaration + } + + override fun visitConstructor(declaration: IrConstructor): IrStatement { + val containingClass = declaration.parentAsClass + + // TODO local (non-enum) class in enum class constructor? + val previous = enumConstructorCallTransformer + + if (containingClass.kind == ClassKind.ENUM_ENTRY) { + assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } + val entry = irClass.declarations.filterIsInstance().single { it.correspondingClass == containingClass } + enumConstructorCallTransformer = InEnumEntryClassConstructor(entry) + } else if (containingClass.kind == ClassKind.ENUM_CLASS) { + assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } + enumConstructorCallTransformer = InEnumClassConstructor(declaration) + } + + val result = super.visitConstructor(declaration) + + enumConstructorCallTransformer = previous + + return result + } + + override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression { + expression.transformChildrenVoid(this) + + val callTransformer = enumConstructorCallTransformer ?: + throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) + + + return callTransformer.transform(expression) + } + + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { + expression.transformChildrenVoid(this) + + 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()) + + return callTransformer.transform(expression) + } + return expression + } + + override fun visitGetValue(expression: IrGetValue): IrExpression { + val parameter = expression.symbol.owner + val loweredParameter = loweredEnumConstructorParameters[parameter] + return if (loweredParameter == null) { + expression + } else { + IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type, + loweredParameter.symbol, expression.origin) + } + } + } + } +} + +private val IrValueParameter.loweredIndex: Int get() = index + 2 + +private class ParameterMapper(superConstructor: IrConstructor, + val constructor: IrConstructor, + val useLoweredIndex: Boolean) : IrElementTransformerVoid() { + private val valueParameters = superConstructor.valueParameters.toSet() + + override fun visitGetValue(expression: IrGetValue): IrExpression { + + val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression + if (valueParameters.contains(superParameter)) { + val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index + val parameter = constructor.valueParameters[index] + return IrGetValueImpl( + expression.startOffset, expression.endOffset, + parameter.type, + parameter.symbol) + } + return expression + } +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt index d68ef2b831a..c457f10ef28 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt @@ -488,7 +488,7 @@ internal object DataFlowIR { }, data = null) } - private fun IrClass.isFinal() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS + private fun IrClass.isFinal() = modality == Modality.FINAL fun mapClassReferenceType(irClass: IrClass, eraseLocalObjects: Boolean = true): Type { // Do not try to devirtualize ObjC classes.