[JS IR BE] Use static fields instead of variables in enum lowering

This commit is contained in:
Svyatoslav Kuzmich
2019-05-22 12:57:11 +03:00
parent 30ada0ccbb
commit cd55e6b1e5
3 changed files with 29 additions and 23 deletions
@@ -19,6 +19,7 @@ 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.builders.declarations.buildField
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import java.util.*
class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass {
@@ -412,17 +414,20 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
}
private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry ->
val type = enumEntry.getType(irClass).makeNullable()
val name = "${enumName}_${enumEntry.name.identifier}_instance"
val result = builder.run {
scope.createTmpVariable(irImplicitCast(irNull(), type), name)
val result = buildField {
name = Name.identifier("${enumName}_${enumEntry.name.identifier}_instance")
type = enumEntry.getType(irClass).makeNullable()
isStatic = true
}.apply {
parent = irClass
initializer = builder.run { irExprBody(irImplicitCast(irNull(), type)) }
}
enumEntry.correspondingClass?.constructors?.forEach {
// Initialize entry instance at the beginning of constructor so it can be used inside constructor body
(it.body as? IrBlockBody)?.apply {
statements.add(0, context.createIrBuilder(it.symbol).run {
irSetVar(result.symbol, irGet(enumEntry.correspondingClass!!.thisReceiver!!))
irSetField(null, result, irGet(enumEntry.correspondingClass!!.thisReceiver!!))
})
}
}
@@ -449,37 +454,39 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
private fun createGetEntryInstanceFuns(
initEntryInstancesFun: IrSimpleFunction,
entryInstances: List<IrVariable>
entryInstances: List<IrField>
) = enumEntries.mapIndexed { index, enumEntry ->
context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) {
buildFunction(createEntryAccessorName(enumName, enumEntry), enumEntry.getType(irClass))
}.apply {
body = context.createIrBuilder(symbol).irBlockBody(this) {
+irCall(initEntryInstancesFun)
+irReturn(irGet(entryInstances[index]))
+irReturn(irGetField(null, entryInstances[index]))
}
}
}
private fun createInitEntryInstancesFun(
entryInstancesInitializedVar: IrVariable,
entryInstances: List<IrVariable>
entryInstancesInitializedField: IrField,
entryInstances: List<IrField>
) = buildFunction("${enumName}_initEntries") {
+irIfThen(irGet(entryInstancesInitializedVar), irReturnUnit())
+irSetVar(entryInstancesInitializedVar.symbol, irBoolean(true))
for ((entry, instanceVar) in enumEntries.zip(entryInstances)) {
+irSetVar(instanceVar.symbol, entry.initializerExpression!!)
+irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit())
+irSetField(null, entryInstancesInitializedField, irBoolean(true))
for ((entry, instanceField) in enumEntries.zip(entryInstances)) {
+irSetField(null, instanceField, entry.initializerExpression!!)
}
}.also {
// entry.initializerExpression can have local declarations
it.acceptVoid(PatchDeclarationParentsVisitor(irClass))
}
private fun createEntryInstancesInitializedVar(): IrVariable {
return builder.scope.createTemporaryVariable(
builder.irBoolean(false),
"${enumName}_entriesInitialized"
)
private fun createEntryInstancesInitializedVar(): IrField = buildField {
name = Name.identifier("${enumName}_entriesInitialized")
type = context.irBuiltIns.booleanType
isStatic = true
}.apply {
parent = irClass
initializer = builder.run { irExprBody(irBoolean(false)) }
}
@@ -38,11 +38,10 @@ class StaticMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
super.visitSimpleFunction(declaration)
}
override fun visitVariable(declaration: IrVariable) {
// TODO: Don't generate variables inside classes
if (declaration.parent is IrClass)
override fun visitField(declaration: IrField) {
if (declaration.parent is IrClass && declaration.isStatic)
staticDeclarationsInClasses.add(declaration)
super.visitVariable(declaration)
super.visitField(declaration)
}
})
@@ -170,7 +170,7 @@ fun IrBuilderWithScope.irGetField(receiver: IrExpression?, field: IrField) =
IrGetFieldImpl(startOffset, endOffset, field.symbol, field.type, receiver)
fun IrBuilderWithScope.irSetField(receiver: IrExpression?, field: IrField, value: IrExpression) =
IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, field.type)
IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, context.irBuiltIns.unitType)
fun IrBuilderWithScope.irGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
IrGetObjectValueImpl(startOffset, endOffset, type, classSymbol)