From 4fc135709e53bf42126f4aa052216b52e78827df Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 20 Oct 2016 10:56:15 +0300 Subject: [PATCH] Inner classes lowering: remap old constructor parameters. --- .../backend/jvm/codegen/FunctionCodegen.kt | 2 +- .../backend/jvm/lower/InnerClassesLowering.kt | 18 +++++++-- .../backend/jvm/lower/InterfaceLowering.kt | 13 +------ .../backend/jvm/lower/VariableRemapper.kt | 39 +++++++++++++++++++ .../ir/box/closureConversion/innerClass2.kt | 7 ++++ .../ir/IrOnlyBoxCodegenTestGenerated.java | 6 +++ 6 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/VariableRemapper.kt create mode 100644 compiler/testData/ir/box/closureConversion/innerClass2.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index 5fb716ecf39..1f4995d6944 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -46,7 +46,7 @@ class FunctionCodegen(val irFunction: IrFunction, val classCodegen: ClassCodegen doGenerate() } catch (e: Throwable) { - throw RuntimeException("${e.message} + while generating code for:\n${irFunction.dump()}", e) + throw RuntimeException("${e.message} while generating code for:\n${irFunction.dump()}", e) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InnerClassesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InnerClassesLowering.kt index 7e826725c4f..cd735c0089c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InnerClassesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InnerClassesLowering.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.utils.addToStdlib.singletonList +import java.util.* class InnerClassesLowering(val context: JvmBackendContext) : ClassLoweringPass { override fun lower(irClass: IrClass) { @@ -42,13 +43,16 @@ class InnerClassesLowering(val context: JvmBackendContext) : ClassLoweringPass { private inner class InnerClassTransformer(val irClass: IrClass) { val classDescriptor = irClass.descriptor - private lateinit var outerThisFieldDescriptor: PropertyDescriptor + lateinit var outerThisFieldDescriptor: PropertyDescriptor + + val oldConstructorParameterToNew = HashMap() fun lowerInnerClass() { if (!irClass.descriptor.isInner) return createOuterThisField() lowerConstructors() + lowerConstructorParameterUsages() lowerOuterThisReferences() } @@ -79,6 +83,10 @@ class InnerClassesLowering(val context: JvmBackendContext) : ClassLoweringPass { val newDescriptor = context.specialDescriptorsFactory.getInnerClassConstructorWithOuterThisParameter(oldDescriptor) val outerThisValueParameter = newDescriptor.valueParameters[0] + oldDescriptor.valueParameters.forEach { oldValueParameter -> + oldConstructorParameterToNew[oldValueParameter] = newDescriptor.valueParameters[oldValueParameter.index + 1] + } + val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}") val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall } @@ -111,6 +119,10 @@ class InnerClassesLowering(val context: JvmBackendContext) : ClassLoweringPass { ) } + private fun lowerConstructorParameterUsages() { + irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew)) + } + private fun lowerOuterThisReferences() { irClass.transformChildrenVoid(object : IrElementTransformerVoid() { override fun visitGetValue(expression: IrGetValue): IrExpression { @@ -179,7 +191,7 @@ class InnerClassConstructorCallsLowering(val context: JvmBackendContext) : BodyL newCall.putValueArgument(0, dispatchReceiver) for (i in 1 .. newCallee.valueParameters.lastIndex) { - newCall.putValueArgument(i, expression.getValueArgument(i)) + newCall.putValueArgument(i, expression.getValueArgument(i - 1)) } return newCall @@ -200,7 +212,7 @@ class InnerClassConstructorCallsLowering(val context: JvmBackendContext) : BodyL newCall.putValueArgument(0, dispatchReceiver) for (i in 1 .. newCallee.valueParameters.lastIndex) { - newCall.putValueArgument(i, expression.getValueArgument(i)) + newCall.putValueArgument(i, expression.getValueArgument(i - 1)) } return newCall diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt index 8753f6338b2..db6c43d2073 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt @@ -31,9 +31,6 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrGetValue -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JvmAbi @@ -66,7 +63,7 @@ class InterfaceLowering(val state: GenerationState) : IrElementTransformerVoid() members.add(newFunction) it.body = null - val mapping: Map = + val mapping: Map = ( listOf(it.descriptor.dispatchReceiverParameter!!, it.descriptor.extensionReceiverParameter).filterNotNull() + it.descriptor.valueParameters @@ -133,11 +130,3 @@ class InterfaceLowering(val state: GenerationState) : IrElementTransformerVoid() } } - -class VariableRemapper(val mapping: Map): IrElementTransformerVoid() { - - override fun visitGetValue(expression: IrGetValue): IrExpression = - mapping[expression.descriptor]?.let { loweredParameter -> - IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter, expression.origin) - } ?: expression -} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/VariableRemapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/VariableRemapper.kt new file mode 100644 index 00000000000..b09159a668d --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/VariableRemapper.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ValueDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid + +abstract class AbstractVariableRemapper : IrElementTransformerVoid() { + protected abstract fun remapVariable(value: ValueDescriptor): ValueDescriptor? + + override fun visitGetValue(expression: IrGetValue): IrExpression = + remapVariable(expression.descriptor)?.let { + IrGetValueImpl(expression.startOffset, expression.endOffset, it, expression.origin) + } ?: expression +} + +class VariableRemapper(val mapping: Map): AbstractVariableRemapper() { + override fun remapVariable(value: ValueDescriptor): ValueDescriptor? = + mapping[value] +} \ No newline at end of file diff --git a/compiler/testData/ir/box/closureConversion/innerClass2.kt b/compiler/testData/ir/box/closureConversion/innerClass2.kt new file mode 100644 index 00000000000..064bb4623e6 --- /dev/null +++ b/compiler/testData/ir/box/closureConversion/innerClass2.kt @@ -0,0 +1,7 @@ +class Outer(val x: String) { + inner class Inner(val y: String) { + val z = x + y + } +} + +fun box() = Outer("O").Inner("K").z \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java index ede6dd32ed3..29f9f874f70 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java @@ -115,6 +115,12 @@ public class IrOnlyBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTest doTest(fileName); } + @TestMetadata("innerClass2.kt") + public void testInnerClass2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/innerClass2.kt"); + doTest(fileName); + } + @TestMetadata("mutable1.kt") public void testMutable1() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/mutable1.kt");