[K/N][IR] Fix for https://youtrack.jetbrains.com/issue/KT-47669
Outer this references should be lowered before inliner
This commit is contained in:
+92
-71
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -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()!!)) {
|
||||
|
||||
Reference in New Issue
Block a user