Outer this references should be lowered before inliner
This commit is contained in:
Igor Chevdar
2021-09-15 14:04:47 +05:00
committed by Space
parent 03db8e9c43
commit cc75b45479
2 changed files with 94 additions and 71 deletions
@@ -19,14 +19,103 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal class OuterThisLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
if (!irClass.isInner) return
irClass.transformChildrenVoid(Transformer(irClass, irClass))
}
fun lower(irFunction: IrFunction) {
var parent = irFunction.parent
var irClass: IrClass? = null
while (parent !is IrPackageFragment) {
irClass = parent as? IrClass
if (irClass != null) break
parent = (parent as IrDeclaration).parent
}
if (irClass == null || !irClass.isInner) return
irFunction.body?.transformChildrenVoid(Transformer(irClass, irFunction))
}
private inner class Transformer(val irClass: IrClass, val container: IrDeclaration) : IrElementTransformerVoidWithContext() {
override fun visitClassNew(declaration: IrClass): IrStatement {
// Skip nested.
return declaration
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val implicitThisClass = (expression.symbol.owner.parent as? IrClass) ?: return expression
if (implicitThisClass == irClass) return expression
val parentScopeSymbols = listOf(container.symbol) + allScopes.map { it.scope.scopeOwnerSymbol }
var functionSymbol: IrFunctionSymbol? = null
for (i in parentScopeSymbols.size - 1 downTo 0) {
val currentSymbol = parentScopeSymbols[i] as? IrFunctionSymbol ?: break
functionSymbol = currentSymbol
}
if (functionSymbol == null) return expression
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
var irThis: IrExpression
var innerClass: IrClass
if ((functionSymbol as? IrConstructorSymbol)?.owner?.parentAsClass == irClass) {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = irClass.parent as? IrClass ?: error("No containing class for inner class ${irClass.render()}")
val thisParameter = functionSymbol.owner.dispatchReceiverParameter!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} else {
innerClass = irClass
val currentFunctionReceiver = functionSymbol.owner.dispatchReceiverParameter
val thisParameter =
if (currentFunctionReceiver?.type?.classifierOrNull == irClass.symbol)
currentFunctionReceiver
else
irClass.thisReceiver!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
}
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.specialDeclarationsFactory.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.dump()}: $outer")
}
return irThis
}
}
}
internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
OuterThisLowering(context).lower(irClass)
InnerClassTransformer(irClass).lowerInnerClass()
}
@@ -45,7 +134,6 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
if (!irClass.isInner) return
createOuterThisField()
lowerOuterThisReferences()
lowerConstructors()
}
@@ -85,73 +173,6 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
return irConstructor
}
private fun lowerOuterThisReferences() {
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
override fun visitClassNew(declaration: IrClass): IrStatement {
// Skip nested.
return declaration
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val implicitThisClass = (expression.symbol.owner.parent as? IrClass) ?: return expression
if (implicitThisClass == irClass) return expression
val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
var irThis: IrExpression
var innerClass: IrClass
if (constructorSymbol == null || constructorSymbol.owner.parentAsClass != irClass) {
innerClass = irClass
val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction
val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter
val thisParameter =
if (currentFunctionReceiver?.type?.classifierOrNull == irClass.symbol)
currentFunctionReceiver
else
irClass.thisReceiver!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} else {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = irClass.parent as? IrClass ?:
throw AssertionError("No containing class for inner class ${irClass.dump()}")
val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
}
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.specialDeclarationsFactory.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.dump()}: $outer")
}
return irThis
}
})
}
}
}
@@ -40,6 +40,8 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
SharedVariablesLowering(context).lower(body, function)
OuterThisLowering(context).lower(function)
LocalClassesInInlineLambdasLowering(context).lower(body, function)
if (context.llvmModuleSpecification.containsPackageFragment(function.getPackageFragment()!!)) {