[JS IR BE] Fix EnumClassLowering
* make it incremental * fix access to enum entry from different module * drop ExternalEnumLowering
This commit is contained in:
@@ -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<IrEnumEntrySymbol, () -> IrExpression>()
|
||||
val enumEntryToGetInstanceFunction = mutableMapOf<IrEnumEntrySymbol, IrSimpleFunction>()
|
||||
val enumEntryExternalToInstanceField = mutableMapOf<IrEnumEntrySymbol, IrField>()
|
||||
val callableReferencesCache = mutableMapOf<CallableReferenceKey, IrSimpleFunction>()
|
||||
|
||||
val coroutineGetContext: IrFunctionSymbol
|
||||
|
||||
@@ -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)
|
||||
|
||||
+62
-14
@@ -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<IrEnumEntry>()
|
||||
@@ -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<IrVariable>
|
||||
) = 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
|
||||
}
|
||||
|
||||
-56
@@ -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<IrEnumEntry>().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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user