[JS IR] Fix backend to make it possible lower partially loaded IR
This commit is contained in:
committed by
TeamCityServer
parent
2ca74174d3
commit
ebf17188cb
+149
-143
@@ -79,58 +79,62 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
var delegatingCtorCall: IrDelegatingConstructorCall? = null
|
var delegatingCtorCall: IrDelegatingConstructorCall? = null
|
||||||
var setMemberField: IrSetField? = null
|
var setMemberField: IrSetField? = null
|
||||||
|
|
||||||
initFunction.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
initFunction.body = irConstructor.body?.let { body ->
|
||||||
val origParameterSymbol = irConstructor.valueParameters.single().symbol
|
context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
statements += context.createIrBuilder(initFunction.symbol).irBlockBody(initFunction) {
|
val origParameterSymbol = irConstructor.valueParameters.single().symbol
|
||||||
val builder = this
|
statements += context.createIrBuilder(initFunction.symbol).irBlockBody(initFunction) {
|
||||||
fun unboxedInlineClassValue() = builder.irReinterpretCast(
|
val builder = this
|
||||||
builder.irGet(initFunction.valueParameters.single()),
|
fun unboxedInlineClassValue() = builder.irReinterpretCast(
|
||||||
type = klass.defaultType,
|
builder.irGet(initFunction.valueParameters.single()),
|
||||||
)
|
type = klass.defaultType,
|
||||||
|
)
|
||||||
|
|
||||||
(irConstructor.body as IrBlockBody).deepCopyWithSymbols(initFunction).statements.forEach { statement ->
|
(body as IrBlockBody).deepCopyWithSymbols(initFunction).statements.forEach { statement ->
|
||||||
+statement.transformStatement(object : IrElementTransformerVoid() {
|
+statement.transformStatement(object : IrElementTransformerVoid() {
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
delegatingCtorCall = expression.deepCopyWithSymbols(irConstructor)
|
delegatingCtorCall = expression.deepCopyWithSymbols(irConstructor)
|
||||||
return builder.irBlock {} // Removing delegating constructor call
|
return builder.irBlock {} // Removing delegating constructor call
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField): IrExpression {
|
|
||||||
val isMemberFieldSet = expression.symbol.owner.parent == klass
|
|
||||||
if (isMemberFieldSet) {
|
|
||||||
setMemberField = expression.deepCopyWithSymbols(irConstructor)
|
|
||||||
}
|
}
|
||||||
expression.transformChildrenVoid()
|
|
||||||
if (isMemberFieldSet) {
|
override fun visitSetField(expression: IrSetField): IrExpression {
|
||||||
return expression.value
|
val isMemberFieldSet = expression.symbol.owner.parent == klass
|
||||||
|
if (isMemberFieldSet) {
|
||||||
|
setMemberField = expression.deepCopyWithSymbols(irConstructor)
|
||||||
|
}
|
||||||
|
expression.transformChildrenVoid()
|
||||||
|
if (isMemberFieldSet) {
|
||||||
|
return expression.value
|
||||||
|
}
|
||||||
|
return expression
|
||||||
}
|
}
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField): IrExpression {
|
override fun visitGetField(expression: IrGetField): IrExpression {
|
||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
if (expression.symbol.owner.parent == klass)
|
if (expression.symbol.owner.parent == klass)
|
||||||
return builder.irGet(initFunction.valueParameters.single())
|
return builder.irGet(initFunction.valueParameters.single())
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
if (expression.symbol.owner.parent == klass)
|
if (expression.symbol.owner.parent == klass)
|
||||||
return unboxedInlineClassValue()
|
return unboxedInlineClassValue()
|
||||||
if (expression.symbol == origParameterSymbol)
|
if (expression.symbol == origParameterSymbol)
|
||||||
return builder.irGet(initFunction.valueParameters.single())
|
return builder.irGet(initFunction.valueParameters.single())
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+irReturn(unboxedInlineClassValue())
|
+irReturn(unboxedInlineClassValue())
|
||||||
}.statements
|
}.statements
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
irConstructor.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
if (irConstructor.body != null) {
|
||||||
statements += delegatingCtorCall!!
|
irConstructor.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
statements += setMemberField!!
|
delegatingCtorCall?.let { statements += it }
|
||||||
|
setMemberField?.let { statements += it }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return listOf(irConstructor, initFunction)
|
return listOf(irConstructor, initFunction)
|
||||||
@@ -142,70 +146,72 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
val irClass = irConstructor.parentAsClass
|
val irClass = irConstructor.parentAsClass
|
||||||
|
|
||||||
// Copied and adapted from Kotlin/Native InlineClassTransformer
|
// Copied and adapted from Kotlin/Native InlineClassTransformer
|
||||||
staticMethod.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
staticMethod.body = irConstructor.body?.let { constructorBody ->
|
||||||
statements += context.createIrBuilder(staticMethod.symbol).irBlockBody(staticMethod) {
|
context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
|
statements += context.createIrBuilder(staticMethod.symbol).irBlockBody(staticMethod) {
|
||||||
|
|
||||||
// Secondary ctors of inline class must delegate to some other constructors.
|
// Secondary ctors of inline class must delegate to some other constructors.
|
||||||
// Use these delegating call later to initialize this variable.
|
// Use these delegating call later to initialize this variable.
|
||||||
lateinit var thisVar: IrVariable
|
lateinit var thisVar: IrVariable
|
||||||
val parameterMapping = staticMethod.valueParameters.associateBy {
|
val parameterMapping = staticMethod.valueParameters.associateBy {
|
||||||
irConstructor.valueParameters[it.index].symbol
|
irConstructor.valueParameters[it.index].symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
(irConstructor.body as IrBlockBody).statements.forEach { statement ->
|
(constructorBody as IrBlockBody).statements.forEach { statement ->
|
||||||
+statement.transformStatement(object : IrElementTransformerVoid() {
|
+statement.transformStatement(object : IrElementTransformerVoid() {
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
expression.transformChildrenVoid()
|
expression.transformChildrenVoid()
|
||||||
// Static function for delegating constructors return unboxed instance of inline class
|
// Static function for delegating constructors return unboxed instance of inline class
|
||||||
expression.type = irClass.defaultType
|
expression.type = irClass.defaultType
|
||||||
return irBlock(expression) {
|
return irBlock(expression) {
|
||||||
thisVar = createTmpVariable(
|
thisVar = createTmpVariable(
|
||||||
expression,
|
expression,
|
||||||
irType = irClass.defaultType
|
irType = irClass.defaultType
|
||||||
)
|
)
|
||||||
thisVar.parent = staticMethod
|
thisVar.parent = staticMethod
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
|
||||||
expression.transformChildrenVoid()
|
|
||||||
if (expression.symbol == irClass.thisReceiver?.symbol) {
|
|
||||||
return irGet(thisVar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterMapping[expression.symbol]?.let { return irGet(it) }
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
return expression
|
expression.transformChildrenVoid()
|
||||||
}
|
if (expression.symbol == irClass.thisReceiver?.symbol) {
|
||||||
|
return irGet(thisVar)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
parameterMapping[expression.symbol]?.let { return irGet(it) }
|
||||||
expression.transformChildrenVoid()
|
return expression
|
||||||
parameterMapping[expression.symbol]?.let { return irSet(it.symbol, expression.value) }
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
|
||||||
declaration.transformChildrenVoid(this)
|
|
||||||
if (declaration.parent == irConstructor)
|
|
||||||
declaration.parent = staticMethod
|
|
||||||
return declaration
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
|
||||||
expression.transformChildrenVoid()
|
|
||||||
if (expression.returnTargetSymbol == irConstructor.symbol) {
|
|
||||||
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
|
|
||||||
+expression.value
|
|
||||||
+irGet(thisVar)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return expression
|
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
||||||
}
|
expression.transformChildrenVoid()
|
||||||
|
parameterMapping[expression.symbol]?.let { return irSet(it.symbol, expression.value) }
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
})
|
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
||||||
}
|
declaration.transformChildrenVoid(this)
|
||||||
+irReturn(irGet(thisVar))
|
if (declaration.parent == irConstructor)
|
||||||
}.statements
|
declaration.parent = staticMethod
|
||||||
|
return declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
expression.transformChildrenVoid()
|
||||||
|
if (expression.returnTargetSymbol == irConstructor.symbol) {
|
||||||
|
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
|
||||||
|
+expression.value
|
||||||
|
+irGet(thisVar)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
+irReturn(irGet(thisVar))
|
||||||
|
}.statements
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,57 +219,57 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
// TODO: Support fake-overridden methods without boxing
|
// TODO: Support fake-overridden methods without boxing
|
||||||
if (function.isStaticMethodOfClass || !function.isReal) return // TODO error()
|
if (function.isStaticMethodOfClass || !function.isReal) return // TODO error()
|
||||||
|
|
||||||
val functionBody = function.body
|
|
||||||
|
|
||||||
// Move function body to static method, transforming value parameters and nested declarations
|
// Move function body to static method, transforming value parameters and nested declarations
|
||||||
staticMethod.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
staticMethod.body = function.body?.let { functionBody ->
|
||||||
statements.addAll((functionBody as IrBlockBody).statements)
|
context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
|
statements.addAll((functionBody as IrBlockBody).statements)
|
||||||
|
|
||||||
transformChildrenVoid(object : IrElementTransformerVoid() {
|
transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
||||||
declaration.transformChildrenVoid(this)
|
declaration.transformChildrenVoid(this)
|
||||||
if (declaration.parent == function)
|
if (declaration.parent == function)
|
||||||
declaration.parent = staticMethod
|
declaration.parent = staticMethod
|
||||||
|
|
||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
|
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
|
||||||
|
|
||||||
return context.createIrBuilder(staticMethod.symbol).irGet(
|
return context.createIrBuilder(staticMethod.symbol).irGet(
|
||||||
when (valueDeclaration) {
|
when (valueDeclaration) {
|
||||||
function.dispatchReceiverParameter, function.parentAsClass.thisReceiver ->
|
function.dispatchReceiverParameter, function.parentAsClass.thisReceiver ->
|
||||||
staticMethod.valueParameters[0]
|
staticMethod.valueParameters[0]
|
||||||
|
|
||||||
function.extensionReceiverParameter ->
|
function.extensionReceiverParameter ->
|
||||||
staticMethod.valueParameters[1]
|
staticMethod.valueParameters[1]
|
||||||
|
|
||||||
in function.valueParameters -> {
|
in function.valueParameters -> {
|
||||||
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
||||||
staticMethod.valueParameters[valueDeclaration.index + offset]
|
staticMethod.valueParameters[valueDeclaration.index + offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return expression
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
else -> return expression
|
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
||||||
}
|
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitSetValue(expression)
|
||||||
)
|
expression.transformChildrenVoid()
|
||||||
}
|
return context.createIrBuilder(staticMethod.symbol).irSet(
|
||||||
|
when (valueDeclaration) {
|
||||||
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
in function.valueParameters -> {
|
||||||
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitSetValue(expression)
|
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
||||||
expression.transformChildrenVoid()
|
staticMethod.valueParameters[valueDeclaration.index + offset].symbol
|
||||||
return context.createIrBuilder(staticMethod.symbol).irSet(
|
}
|
||||||
when (valueDeclaration) {
|
else -> return expression
|
||||||
in function.valueParameters -> {
|
},
|
||||||
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
expression.value
|
||||||
staticMethod.valueParameters[valueDeclaration.index + offset].symbol
|
)
|
||||||
}
|
}
|
||||||
else -> return expression
|
})
|
||||||
},
|
}
|
||||||
expression.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -394,7 +394,9 @@ class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) :
|
|||||||
|
|
||||||
irClass.enumEntries.forEach { entry ->
|
irClass.enumEntries.forEach { entry ->
|
||||||
entry.correspondingField?.let { instanceField ->
|
entry.correspondingField?.let { instanceField ->
|
||||||
+irSetField(null, instanceField, entry.initializerExpression!!.expression.deepCopyWithSymbols(it))
|
entry.initializerExpression?.let { initializer ->
|
||||||
|
+irSetField(null, instanceField, initializer.expression.deepCopyWithSymbols(it))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-5
@@ -124,14 +124,26 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : Declaratio
|
|||||||
private fun generateInitBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction) {
|
private fun generateInitBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction) {
|
||||||
val thisParam = delegate.valueParameters.last()
|
val thisParam = delegate.valueParameters.last()
|
||||||
val oldThisReceiver = irClass.thisReceiver!!
|
val oldThisReceiver = irClass.thisReceiver!!
|
||||||
val constructorBody = constructor.body!!
|
val constructorBody = constructor.body
|
||||||
val oldValueParameters = constructor.valueParameters + oldThisReceiver
|
val oldValueParameters = constructor.valueParameters + oldThisReceiver
|
||||||
|
|
||||||
// TODO: replace parameters as well
|
// TODO: replace parameters as well
|
||||||
delegate.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
if (constructorBody != null) {
|
||||||
statements += (constructorBody.deepCopyWithSymbols(delegate) as IrStatementContainer).statements
|
delegate.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
statements += JsIrBuilder.buildReturn(delegate.symbol, JsIrBuilder.buildGetValue(thisParam.symbol), context.irBuiltIns.nothingType)
|
statements += (constructorBody.deepCopyWithSymbols(delegate) as IrStatementContainer).statements
|
||||||
transformChildrenVoid(ThisUsageReplaceTransformer(constructor.symbol, delegate.symbol, oldValueParameters.zip(delegate.valueParameters).toMap()))
|
statements += JsIrBuilder.buildReturn(
|
||||||
|
delegate.symbol,
|
||||||
|
JsIrBuilder.buildGetValue(thisParam.symbol),
|
||||||
|
context.irBuiltIns.nothingType
|
||||||
|
)
|
||||||
|
transformChildrenVoid(
|
||||||
|
ThisUsageReplaceTransformer(
|
||||||
|
constructor.symbol,
|
||||||
|
delegate.symbol,
|
||||||
|
oldValueParameters.zip(delegate.valueParameters).toMap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user