Refactor InnerClassesLowering

This commit is contained in:
pyos
2019-03-15 10:18:28 +01:00
committed by max-kammerer
parent a2adfd0cc0
commit 7e8db4cc4a
@@ -10,9 +10,10 @@ import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -20,151 +21,92 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import java.util.*
val innerClassesPhase = makeIrFilePhase(
::InnerClassesLowering,
name = "InnerClasses",
description = "Move inner classes to toplevel"
description = "Add 'outer this' fields to inner classes"
)
class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
private val IrValueSymbol.classForImplicitThis: IrClass?
// TODO: is this the correct way to get the class?
// -1 means value is either IMPLICIT or EXTENSION receiver
get() = if (this is IrValueParameterSymbol && owner.index == -1 && owner.name.isSpecial /* <this> */)
owner.type.classifierOrNull?.owner as IrClass
else
null
override fun lower(irClass: IrClass) {
InnerClassTransformer(irClass).lowerInnerClass()
}
private inner class InnerClassTransformer(val irClass: IrClass) {
lateinit var outerThisField: IrField
if (!irClass.isInner) return
val parentThisField = context.declarationFactory.getOuterThisField(irClass)
val oldConstructorParameterToNew = HashMap<IrValueParameter, IrValueParameter>()
fun lowerInnerClass() {
if (!irClass.isInner) return
createOuterThisField()
lowerConstructors()
lowerConstructorParameterUsages()
lowerOuterThisReferences()
}
private fun createOuterThisField() {
val field = context.declarationFactory.getOuterThisField(irClass)
outerThisField = field
irClass.declarations += field
}
private fun lowerConstructors() {
irClass.transformDeclarationsFlat { irMember ->
if (irMember is IrConstructor)
listOf(lowerConstructor(irMember))
else
null
}
}
private fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
val startOffset = irConstructor.startOffset
val endOffset = irConstructor.endOffset
fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
val loweredConstructor = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(irConstructor)
val outerThisValueParameter = loweredConstructor.valueParameters[0].symbol
val outerThisParameter = loweredConstructor.valueParameters[0]
irConstructor.valueParameters.forEach { old ->
oldConstructorParameterToNew[old] = loweredConstructor.valueParameters[old.index + 1]
}
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall }
// Initializing constructor: initialize 'this.this$0' with '$outer'
blockBody.statements.add(
0,
IrSetFieldImpl(
startOffset, endOffset, outerThisField.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
IrGetValueImpl(startOffset, endOffset, outerThisValueParameter),
context.irBuiltIns.unitType
)
)
if (instanceInitializerIndex < 0) {
// Delegating constructor: invoke old constructor with dispatch receiver '$outer'
val delegatingConstructorCall = (blockBody.statements.find { it is IrDelegatingConstructorCall }
?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
) as IrDelegatingConstructorCall
delegatingConstructorCall.dispatchReceiver = IrGetValueImpl(
delegatingConstructorCall.startOffset, delegatingConstructorCall.endOffset, outerThisValueParameter
)
context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply {
blockBody.statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter)))
}
if (blockBody.statements.find { it is IrInstanceInitializerCall } == null) {
val delegatingConstructorCall =
blockBody.statements.find { it is IrDelegatingConstructorCall } as IrDelegatingConstructorCall?
?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
delegatingConstructorCall.apply { dispatchReceiver = IrGetValueImpl(startOffset, endOffset, outerThisParameter.symbol) }
}
blockBody.patchDeclarationParents(loweredConstructor)
loweredConstructor.body = blockBody
return loweredConstructor
}
private fun lowerConstructorParameterUsages() {
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
}
irClass.declarations += parentThisField
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
private fun lowerOuterThisReferences() {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
// TODO: maybe add another transformer that skips specified elements
override fun visitClass(declaration: IrClass): IrStatement =
declaration
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
override fun visitClass(declaration: IrClass): IrStatement =
//TODO: maybe add another transformer that skips specified elements
declaration
val implicitThisClass = expression.symbol.classForImplicitThis
if (implicitThisClass == null || implicitThisClass == irClass) return expression
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
val implicitThisClass = expression.symbol.getClassForImplicitThis() ?: return expression
if (implicitThisClass == irClass) return expression
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin)
var innerClass = irClass
while (innerClass != implicitThisClass) {
if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion.
return expression
}
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
val outer = innerClass.parent
innerClass = outer as? IrClass ?:
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin)
var innerClass = irClass
while (innerClass != implicitThisClass) {
if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion.
return expression
}
return irThis
}
})
}
private fun IrValueSymbol.getClassForImplicitThis(): IrClass? {
//TODO: is it correct way to get class
if (this is IrValueParameterSymbol) {
val declaration = owner
if (declaration.index == -1) { // means value is either IMPLICIT or EXTENSION receiver
if (declaration.name.isSpecial) { // whether name is <this>
return owner.type.classifierOrNull?.owner as IrClass
}
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
innerClass = innerClass.parentAsClass
}
return irThis
}
return null
}
})
}
}