[JS IR] Add guard into init properties function
^KT-43222 fixed
This commit is contained in:
+93
-45
@@ -9,54 +9,113 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
|||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrGetField
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrSetField
|
import org.jetbrains.kotlin.ir.expressions.IrSetField
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
||||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import kotlin.collections.component1
|
||||||
|
import kotlin.collections.component2
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
class PropertyLazyInitLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
class PropertyLazyInitLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||||
private val irBuiltIns
|
private val irBuiltIns
|
||||||
get() = context.irBuiltIns
|
get() = context.irBuiltIns
|
||||||
|
|
||||||
|
private val calculator = JsIrArithBuilder(context)
|
||||||
|
|
||||||
|
private val irFactory
|
||||||
|
get() = context.irFactory
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
val initializers = PropertyInitializerMover(context).process(irFile)
|
val initializers = PropertyInitializerMover(context).process(irFile)
|
||||||
val irFactory = context.irFactory
|
|
||||||
if (initializers.isNotEmpty()) {
|
if (initializers.isEmpty()) return
|
||||||
irFactory.addFunction(irFile) {
|
|
||||||
name = Name.identifier("init properties ${irFile.kotlinFqName}")
|
val fileName = irFile.name
|
||||||
returnType = irBuiltIns.unitType
|
val initialisedField = irFactory.createInitialisationField(fileName)
|
||||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
.apply {
|
||||||
}.apply {
|
irFile.declarations.add(this)
|
||||||
body = irFactory.createBlockBody(
|
parent = irFile
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
initializers
|
|
||||||
.map { (field, expression) ->
|
|
||||||
createIrSetField(field, expression)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irFactory.addFunction(irFile) {
|
||||||
|
name = Name.identifier("init properties $fileName")
|
||||||
|
returnType = irBuiltIns.unitType
|
||||||
|
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||||
|
}.apply {
|
||||||
|
buildPropertiesInitializationBody(
|
||||||
|
initializers,
|
||||||
|
initialisedField
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrFactory.createInitialisationField(fileName: String): IrField =
|
||||||
|
buildField {
|
||||||
|
name = Name.identifier("properties initialised $fileName")
|
||||||
|
type = irBuiltIns.booleanType
|
||||||
|
isStatic = true
|
||||||
|
isFinal = true
|
||||||
|
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrSimpleFunction.buildPropertiesInitializationBody(
|
||||||
|
initializers: Map<IrField, IrExpression>,
|
||||||
|
initialisedField: IrField
|
||||||
|
) {
|
||||||
|
|
||||||
|
body = irFactory.createBlockBody(
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
buildBodyWithIfGuard(initializers, initialisedField)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildBodyWithIfGuard(
|
||||||
|
initializers: Map<IrField, IrExpression>,
|
||||||
|
initialisedField: IrField
|
||||||
|
): List<IrWhen> {
|
||||||
|
val statements = initializers
|
||||||
|
.map { (field, expression) ->
|
||||||
|
createIrSetField(field, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
val upGuard = createIrSetField(
|
||||||
|
initialisedField,
|
||||||
|
JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||||
|
)
|
||||||
|
|
||||||
|
return JsIrBuilder.buildIfElse(
|
||||||
|
type = irBuiltIns.unitType,
|
||||||
|
cond = calculator.not(createIrGetField(initialisedField)),
|
||||||
|
thenBranch = JsIrBuilder.buildComposite(
|
||||||
|
type = irBuiltIns.unitType,
|
||||||
|
statements = mutableListOf(upGuard).apply { addAll(statements) }
|
||||||
|
)
|
||||||
|
).let { listOf(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createIrGetField(field: IrField): IrGetField {
|
||||||
|
return JsIrBuilder.buildGetField(
|
||||||
|
symbol = field.symbol,
|
||||||
|
receiver = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createIrSetField(field: IrField, expression: IrExpression): IrSetField {
|
private fun createIrSetField(field: IrField, expression: IrExpression): IrSetField {
|
||||||
return IrSetFieldImpl(
|
return JsIrBuilder.buildSetField(
|
||||||
field.startOffset,
|
symbol = field.symbol,
|
||||||
field.endOffset,
|
receiver = null,
|
||||||
field.symbol,
|
value = expression,
|
||||||
null,
|
type = expression.type
|
||||||
expression,
|
|
||||||
expression.type
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,9 +124,9 @@ private class PropertyInitializerMover(
|
|||||||
private val context: JsIrBackendContext
|
private val context: JsIrBackendContext
|
||||||
) : IrElementTransformerVoid() {
|
) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
private val fieldToInitializers = mutableListOf<Pair<IrField, IrExpression>>()
|
private val fieldToInitializers = mutableMapOf<IrField, IrExpression>()
|
||||||
|
|
||||||
fun process(irFile: IrFile): List<Pair<IrField, IrExpression>> {
|
fun process(irFile: IrFile): Map<IrField, IrExpression> {
|
||||||
irFile.transformChildrenVoid(this)
|
irFile.transformChildrenVoid(this)
|
||||||
return fieldToInitializers
|
return fieldToInitializers
|
||||||
}
|
}
|
||||||
@@ -78,25 +137,14 @@ private class PropertyInitializerMover(
|
|||||||
?.takeIf { !it.isConst }
|
?.takeIf { !it.isConst }
|
||||||
?.takeIf { !it.isDelegated }
|
?.takeIf { !it.isDelegated }
|
||||||
?.backingField
|
?.backingField
|
||||||
|
?.takeIf { it !in fieldToInitializers }
|
||||||
?.takeIf { it.initializer != null }
|
?.takeIf { it.initializer != null }
|
||||||
?.let { field ->
|
?.let { field ->
|
||||||
fieldToInitializers.add(field to field.initializer!!.expression)
|
fieldToInitializers[field] = field.initializer!!.expression
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldToInitializers.forEach { it.first.initializer = null }
|
fieldToInitializers.forEach { it.key.initializer = null }
|
||||||
|
|
||||||
return super.visitSimpleFunction(declaration)
|
return super.visitSimpleFunction(declaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFieldAccess(expression: IrFieldAccessExpression): IrExpression {
|
|
||||||
return super.visitFieldAccess(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitField(declaration: IrField): IrStatement {
|
|
||||||
return super.visitField(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBody(body: IrBody): IrBody {
|
|
||||||
return super.visitBody(body)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user