diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 445e3e02c00..226899b5669 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -27,7 +27,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol @@ -113,7 +112,8 @@ class JsIrBackendContext( private val coroutinePackage = module.getPackage(COROUTINE_PACKAGE_FQNAME) private val coroutineIntrinsicsPackage = module.getPackage(COROUTINE_INTRINSICS_PACKAGE_FQNAME) - val enumEntryToGetInstanceFunction = mutableMapOf IrExpression>() + val enumEntryToGetInstanceFunction = mutableMapOf() + val enumEntryExternalToInstanceField = mutableMapOf() val callableReferencesCache = mutableMapOf() val coroutineGetContext: IrFunctionSymbol diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 1b4c3d3e508..7ec46e1dbed 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -73,7 +73,6 @@ fun compile( moduleFragment.files.forEach { irFile -> extension.generate(irFile, context, psi2IrContext.bindingContext) } } - ExternalEnumLowering(context).runOnFilesPostfix(moduleFragment) MoveExternalDeclarationsToSeparatePlace().lower(moduleFragment) ExpectDeclarationsRemoving(context).lower(moduleFragment) CoroutineIntrinsicLowering(context).lower(moduleFragment) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 5fb76d9655b..ba41882f6dd 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -8,22 +8,26 @@ package org.jetbrains.kotlin.ir.backend.js.lower import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irIfThen +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.builders.* 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.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl 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.types.IrType import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.* @@ -34,10 +38,43 @@ import java.util.* class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitGetEnumValue(expression: IrGetEnumValue) = - context.enumEntryToGetInstanceFunction[expression.symbol]!!.invoke() + override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression { + val enumEntry = expression.symbol.owner + val klass = enumEntry.parent as IrClass + return if (klass.isExternal) lowerExternalEnumEntry(enumEntry, klass) else lowerEnumEntry(enumEntry, klass) + } }) } + + private fun lowerExternalEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) = + context.enumEntryExternalToInstanceField.getOrPut(enumEntry.symbol) { createFieldForEntry(enumEntry, klass) }.let { + JsIrBuilder.buildGetField(it.symbol, classAsReceiver(klass), null, klass.defaultType) + } + + private fun classAsReceiver(irClass: IrClass): IrExpression { + val intrinsic = context.intrinsics.jsClass + return JsIrBuilder.buildCall(intrinsic, context.irBuiltIns.anyType, listOf(irClass.defaultType)) + } + + private fun createFieldForEntry(entry: IrEnumEntry, irClass: IrClass): IrField { + val descriptor = WrappedPropertyDescriptor() + val symbol = IrFieldSymbolImpl(descriptor) + return entry.run { + IrFieldImpl(startOffset, endOffset, origin, symbol, name, irClass.defaultType, Visibilities.PUBLIC, false, true, true).also { + descriptor.bind(it) + it.parent = irClass + irClass.declarations += it + } + } + } + + private fun lowerEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) = + context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) { + JsIrBuilder.buildFunction(createEntryAccessorName(klass.name.identifier, enumEntry)).also { + it.returnType = enumEntry.getType(klass) + it.parent = klass + } + }.run { JsIrBuilder.buildCall(symbol) } } class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass { @@ -55,6 +92,12 @@ class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerL } } + +private fun createEntryAccessorName(enumName: String, enumEntry: IrEnumEntry) = + "${enumName}_${enumEntry.name.identifier}_getInstance" + +private fun IrEnumEntry.getType(irClass: IrClass) = (correspondingClass ?: irClass).defaultType + class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) { private val builder = context.createIrBuilder(irClass.symbol) private val enumEntries = irClass.declarations.filterIsInstance() @@ -138,8 +181,7 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: irClass.defaultType, enumEntries.map { irBranch( - irEquals(irString(it.name.identifier), irGet(nameParameter)), - entryInstanceToFunction[it.symbol]!!.invoke() + irEquals(irString(it.name.identifier), irGet(nameParameter)), irCall(entryInstanceToFunction[it.symbol]!!) ) } + irElseBranch(irCall(throwISESymbol)) ) @@ -163,7 +205,7 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: return context.createIrBuilder(valuesFun.symbol).run { irBlockBody { +irReturn( - enumEntries.map { entryInstanceToFunction[it.symbol]!!.invoke() } + enumEntries.map { irCall(entryInstanceToFunction[it.symbol]!!) } .toArrayLiteral(valuesFun.returnType, irClass.defaultType) ) } @@ -209,7 +251,7 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry -> - val type = enumEntry.getType().makeNullable() + val type = enumEntry.getType(irClass).makeNullable() val name = "${enumName}_${enumEntry.name.identifier}_instance" builder.run { scope.createTemporaryVariable(irImplicitCast(irNull(), type), name) @@ -237,14 +279,13 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: initEntryInstancesFun: IrSimpleFunction, entryInstances: List ) = enumEntries.mapIndexed { index, enumEntry -> - buildFunction( - name = "${enumName}_${enumEntry.name.identifier}_getInstance", - returnType = enumEntry.getType() - ) { - +irCall(initEntryInstancesFun) - +irReturn(irGet(entryInstances[index])) + context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) { + buildFunction(createEntryAccessorName(enumName, enumEntry), enumEntry.getType(irClass)) }.apply { - context.enumEntryToGetInstanceFunction[enumEntry.symbol] = { JsIrBuilder.buildCall(this@apply.symbol) } + body = context.createIrBuilder(symbol).irBlockBody(this) { + +irCall(initEntryInstancesFun) + +irReturn(irGet(entryInstances[index])) + } } } @@ -365,6 +406,14 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } } + private fun buildFunction( + name: String, + returnType: IrType = context.irBuiltIns.unitType + ) = JsIrBuilder.buildFunction(name).also { + it.returnType = returnType + it.parent = irClass + } + private fun buildFunction( name: String, returnType: IrType = context.irBuiltIns.unitType, @@ -377,5 +426,4 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier) private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this)) - private fun IrEnumEntry.getType() = (correspondingClass ?: irClass).defaultType } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt deleted file mode 100644 index 069c45b4687..00000000000 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.ir.backend.js.lower - -import org.jetbrains.kotlin.backend.common.ClassLoweringPass -import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext -import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrEnumEntry -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.isEnumClass - -// TODO: Shouldn't it be lazy pass? -class ExternalEnumLowering(val context: JsIrBackendContext) : ClassLoweringPass { - override fun lower(irClass: IrClass) { - if (!irClass.isExternal) return - if (!irClass.isEnumClass) return - - irClass.declarations.filterIsInstance().forEach { - val enumField = createFieldForEntry(it, irClass) - context.enumEntryToGetInstanceFunction[it.symbol] = { - JsIrBuilder.buildGetField(enumField.symbol, classAsReceiver(irClass), null, irClass.defaultType) - } - } - } - - private fun classAsReceiver(irClass: IrClass): IrExpression { - val intrinsic = context.intrinsics.jsClass - return JsIrBuilder.buildCall(intrinsic, context.irBuiltIns.anyType, listOf(irClass.defaultType)) - } - - - private fun createFieldForEntry(entry: IrEnumEntry, irClass: IrClass): IrField { - val descriptor = WrappedPropertyDescriptor() - val symbol = IrFieldSymbolImpl(descriptor) - return entry.run { - IrFieldImpl(startOffset, endOffset, origin, symbol, name, irClass.defaultType, Visibilities.DEFAULT_VISIBILITY, false, true, true ).also { f -> - descriptor.bind(f) - f.parent = irClass - irClass.declarations += f - - } - } - } - - -} \ No newline at end of file