diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt index 8d7df98f408..7f5bc8e10f5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt @@ -4,20 +4,22 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.lower.callsSuper import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl +import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.expressions.IrBlockBody +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.utils.addToStdlib.singletonList @@ -83,6 +85,21 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { private fun lowerOuterThisReferences() { irClass.transformChildrenVoid(object : IrElementTransformerVoid() { + private fun MutableList.push(element: E) = this.add(element) + + private fun MutableList.pop() = this.removeAt(size - 1) + + private fun MutableList.peek(): E? = if (size == 0) null else this[size - 1] + + private val functionsStack = mutableListOf() + + override fun visitFunction(declaration: IrFunction): IrStatement { + functionsStack.push(declaration.descriptor) + val result = super.visitFunction(declaration) + functionsStack.pop() + return result + } + override fun visitGetValue(expression: IrGetValue): IrExpression { expression.transformChildrenVoid(this) @@ -91,12 +108,23 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { if (implicitThisClass == classDescriptor) return expression + val constructorDescriptor = functionsStack.peek()!! as? ConstructorDescriptor + val startOffset = expression.startOffset val endOffset = expression.endOffset val origin = expression.origin - var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter, origin) - var innerClass = classDescriptor + var irThis: IrExpression + var innerClass: ClassDescriptor + if (constructorDescriptor == null) { + innerClass = classDescriptor + irThis = IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter, origin) + } else { + // For constructor we have outer class as dispatchReceiverParameter. + innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?: + throw AssertionError("No containing class for inner class $classDescriptor") + irThis = IrGetValueImpl(startOffset, endOffset, constructorDescriptor.dispatchReceiverParameter!!, origin) + } while (innerClass != implicitThisClass) { if (!innerClass.isInner) { diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index a5fac478d74..c7afcbf613c 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -424,6 +424,11 @@ task innerClass_noPrimaryConstructor(type: RunKonanTest) { source = "codegen/innerClass/noPrimaryConstructor.kt" } +task innerClass_secondaryConstructor(type: RunKonanTest) { + goldValue = "42\n" + source = "codegen/innerClass/secondaryConstructor.kt" +} + task localClass_localHierarchy(type: RunKonanTest) { goldValue = "OK\n" source = "codegen/localClass/localHierarchy.kt" diff --git a/backend.native/tests/codegen/innerClass/secondaryConstructor.kt b/backend.native/tests/codegen/innerClass/secondaryConstructor.kt new file mode 100644 index 00000000000..8b23e100a48 --- /dev/null +++ b/backend.native/tests/codegen/innerClass/secondaryConstructor.kt @@ -0,0 +1,20 @@ +class Outer(val x: Int) { + inner class Inner() { + inner class InnerInner() { + + init { + println(x) + } + + lateinit var s: String + + constructor(s: String) : this() { + this.s = s + } + } + } +} + +fun main(args : Array) { + Outer(42).Inner().InnerInner("zzz") +}