diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt index a99f50b4f79..0012d2a0248 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InnerClassesLowering.kt @@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext 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.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* @@ -28,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +// This pass has to run after LocalDeclarationsLowering, since we don't handle nested functions. val innerClassesPhase = makeIrFilePhase( ::InnerClassesLowering, name = "InnerClasses", @@ -76,21 +79,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass { irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } } irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew)) - irClass.transformChildrenVoid(object : IrElementTransformerVoid() { - private var enclosingConstructor: IrConstructor? = null - - // TODO: maybe add another transformer that skips specified elements - override fun visitClass(declaration: IrClass): IrStatement = + irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { + override fun visitClassNew(declaration: IrClass): IrStatement = declaration - override fun visitConstructor(declaration: IrConstructor): IrStatement = - try { - enclosingConstructor = declaration - super.visitConstructor(declaration) - } finally { - enclosingConstructor = null - } - override fun visitGetValue(expression: IrGetValue): IrExpression { expression.transformChildrenVoid(this) @@ -100,8 +92,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass { val startOffset = expression.startOffset val endOffset = expression.endOffset val origin = expression.origin + val function = currentFunction?.irElement as? IrFunction + val enclosingThisReceiver = function?.dispatchReceiverParameter ?: irClass.thisReceiver!! - var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin) + var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, enclosingThisReceiver.symbol, origin) var innerClass = irClass while (innerClass != implicitThisClass) { if (!innerClass.isInner) { @@ -110,10 +104,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass { return expression } - irThis = if (enclosingConstructor != null && irClass == innerClass) { + irThis = if (function is IrConstructor && irClass == innerClass) { // Might be before a super() call (e.g. an argument to one), in which case the JVM bytecode verifier will reject // an attempt to access the field. Good thing we have a local variable as well. - IrGetValueImpl(startOffset, endOffset, enclosingConstructor!!.valueParameters[0].symbol, origin) + IrGetValueImpl(startOffset, endOffset, function.valueParameters[0].symbol, origin) } else { val outerThisField = context.declarationFactory.getOuterThisField(innerClass) IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 5c2468baee5..4d198b64705 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -234,7 +234,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL functionReferenceClass = buildClass { setSourceRange(irFunctionReference) origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL - name = "${callee.name}\$${functionReferenceCount++}".synthesizedName + name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName kind = ClassKind.CLASS visibility = Visibilities.PUBLIC modality = Modality.FINAL @@ -403,7 +403,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL val argument = when { !unboundArgsSet.contains(parameter) -> // Bound parameter - read from field. - irGetField(irGet(functionReferenceThis.owner), argumentToFieldMap[parameter]!!) + irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!) function.isSuspend && unboundIndex == valueParameters.size -> // For suspend functions the last argument is continuation and it is implicit. TODO() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt index eb90b1cc923..7b1c285c7da 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt @@ -111,7 +111,7 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl target.returnType, target.returnType.classifierOrFail, irCall(target).apply { - dispatchReceiver = irGet(irClass.thisReceiver!!) + dispatchReceiver = irGet(dispatchReceiverParameter!!) target.valueParameters.forEachIndexed { i, irValueParameter -> val type = irValueParameter.type putValueArgument( diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index f82aad3f6cc..dc9faff77fb 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -292,70 +292,79 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class } } - fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List) -> IrExpression) = - buildFun { - setSourceRange(expression) - name = method.name - returnType = method.returnType - visibility = method.visibility - origin = referenceClass.origin - }.apply { - parent = referenceClass - referenceClass.declarations.add(this) - - overriddenSymbols.add(method.symbol) - dispatchReceiverParameter = referenceThis.copyTo(this) - for (parameter in method.valueParameters) - valueParameters.add(parameter.copyTo(this)) - body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { - +irReturn(build(valueParameters)) - } + fun buildOverride( + method: IrSimpleFunction, + build: IrBlockBodyBuilder.(IrValueParameter, List) -> IrExpression + ) = referenceClass.addFunction { + setSourceRange(expression) + name = method.name + returnType = method.returnType + visibility = method.visibility + origin = referenceClass.origin + }.apply { + overriddenSymbols.add(method.symbol) + val thisParameter = referenceThis.copyTo(this) + dispatchReceiverParameter = thisParameter + for (parameter in method.valueParameters) + valueParameters.add(parameter.copyTo(this)) + body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { + +irReturn(build(thisParameter, valueParameters)) } + } val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!! - fun IrBuilderWithScope.setReceiversOn(call: IrCall, valueParameters: List) { + fun IrBuilderWithScope.setReceiversOn( + call: IrCall, + dispatchReceiverParameter: IrValueParameter, + valueParameters: List + ) { var index = 0 call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let { if (expression.dispatchReceiver != null) - irGetField(irGet(referenceThis), receiverField) + irGetField(irGet(dispatchReceiverParameter), receiverField) else irImplicitCast(irGet(valueParameters[index++]), it.type) } call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let { if (expression.extensionReceiver != null) - irGetField(irGet(referenceThis), receiverField) + irGetField(irGet(dispatchReceiverParameter), receiverField) else irImplicitCast(irGet(valueParameters[index++]), it.type) } } - buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { + buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ -> irString(expression.descriptor.name.asString()) } - buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { + buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ -> buildReflectedContainerReference(expression) } - buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { + buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ -> irString(expression.signature) } expression.getter?.owner?.let { getter -> - buildOverride(superClass.functions.single { it.name.asString() == "get" }) { valueParameters -> + buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters -> irGet(getter.returnType, null, getter.symbol).apply { copyTypeArgumentsFrom(expression) - setReceiversOn(this, valueParameters) + setReceiversOn( + this, + dispatchReceiverParameter, + valueParameters + ) } } } expression.setter?.owner?.let { setter -> - buildOverride(superClass.functions.single { it.name.asString() == "set" }) { valueParameters -> - val value = irGet(valueParameters.last()) + buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters -> + val type = setter.valueParameters.last().type + val value = irImplicitCast(irGet(valueParameters.last()), type) irSet(setter.returnType, null, setter.symbol, value).apply { copyTypeArgumentsFrom(expression) - setReceiversOn(this, valueParameters) + setReceiversOn(this, dispatchReceiverParameter, valueParameters) } } }