diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index db5287adbed..81369d41148 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -50,7 +50,7 @@ class JvmLower(val context: JvmBackendContext) { ObjectClassLowering(context).runOnFilePostfix(irFile) InitializersLowering(context).runOnFilePostfix(irFile) SingletonReferencesLowering(context).runOnFilePostfix(irFile) - SyntheticAccessorLowering(context.state).lower(irFile) + SyntheticAccessorLowering(context).lower(irFile) BridgeLowering(context.state).runOnFilePostfix(irFile) TailrecLowering(context).runOnFilePostfix(irFile) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 87d55917f59..a84fe82510b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -17,18 +17,19 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs -import org.jetbrains.kotlin.codegen.AccessorForCallableDescriptor -import org.jetbrains.kotlin.codegen.AccessorForPropertyDescriptor -import org.jetbrains.kotlin.codegen.JvmCodegenUtil -import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -36,13 +37,15 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.types.KotlinType interface StubContext { val irClassContext: IrClassContext @@ -97,7 +100,11 @@ class ContextAnnotator(val state: GenerationState) : ClassLowerWithContext() { } } -class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, IrElementTransformer { +class SyntheticAccessorLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformer { + + private val state = context.state + + var pendingTransformations = mutableListOf>() private val IrClassContext.codegenContext: CodegenContext<*> get() = contextAnnotator.context2Codegen[this]!! @@ -111,12 +118,14 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, contextAnnotator = ContextAnnotator(state) contextAnnotator.lower(irFile) irFile.transform(this, null) + + pendingTransformations.forEach { it() } } override fun visitClass(declaration: IrClass, data: IrClassContext?): IrStatement { val classContext = (declaration.descriptor.codegenContext as StubContext).irClassContext return super.visitClass(declaration, classContext).apply { - lower(classContext) + pendingTransformations.add { lower(classContext) } } } @@ -127,24 +136,24 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, ( accessors.filterIsInstance() + accessors.filterIsInstance().flatMap { - listOf(if (it.isWithSyntheticGetterAccessor) it.getter else null, if (it.isWithSyntheticSetterAccessor) it.setter else null).filterNotNull() + listOfNotNull(if (it.isWithSyntheticGetterAccessor) it.getter else null, if (it.isWithSyntheticSetterAccessor) it.setter else null) } ).filterIsInstance>() - val irClassToAddAccessor = data.irClass + val irClassToAddAccessor = data.irClass allAccessors.forEach { accessor -> - addAccessorToClass(accessor, irClassToAddAccessor, state.typeMapper) + addAccessorToClass(accessor, irClassToAddAccessor, context) } } override fun visitMemberAccess(expression: IrMemberAccessExpression, data: IrClassContext?): IrElement { val superResult = super.visitMemberAccess(expression, data) - return createSyntheticAccessorCallForFunction(superResult, expression, data?.codegenContext, state.typeMapper) + return createSyntheticAccessorCallForFunction(superResult, expression, data?.codegenContext, context) } companion object { - fun createSyntheticAccessorCallForFunction(superResult: IrElement, expression: IrMemberAccessExpression, codegenContext: CodegenContext<*>?, typeMapper: KotlinTypeMapper): IrElement { + fun createSyntheticAccessorCallForFunction(superResult: IrElement, expression: IrMemberAccessExpression, codegenContext: CodegenContext<*>?, context: JvmBackendContext): IrElement { val descriptor = expression.descriptor if (descriptor is FunctionDescriptor) { @@ -152,31 +161,58 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, val accessor = Companion.actualAccessor(descriptor, directAccessor) if (accessor is AccessorForCallableDescriptor<*> && descriptor !is AccessorForCallableDescriptor<*>) { + val isConstructor = descriptor is ConstructorDescriptor val accessorOwner = accessor.containingDeclaration as ClassOrPackageFragmentDescriptor - val staticAccessor = descriptor.toStatic(accessorOwner, Name.identifier(typeMapper.mapAsmMethod(accessor as FunctionDescriptor).name)) //TODO change call - val call = IrCallImpl(expression.startOffset, expression.endOffset, staticAccessor, emptyMap(), expression.origin/*TODO super*/) + val accessorForIr = + accessorToIrAccessor(isConstructor, accessor, context, descriptor, accessorOwner) //TODO change call + + val call = + if (isConstructor && expression is IrDelegatingConstructorCall) + IrDelegatingConstructorCallImpl(expression.startOffset, expression.endOffset, accessorForIr as ClassConstructorDescriptor) + else IrCallImpl(expression.startOffset, expression.endOffset, accessorForIr, emptyMap(), expression.origin/*TODO super*/) //copyAllArgsToValueParams(call, expression) - expression.receiverAndArgs().forEachIndexed { i, irExpression -> + val receiverAndArgs = expression.receiverAndArgs() + receiverAndArgs.forEachIndexed { i, irExpression -> call.putValueArgument(i, irExpression) } + if (isConstructor) { + call.putValueArgument(receiverAndArgs.size, IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.ir.symbols.defaultConstructorMarker.descriptor.defaultType)) + } return call } } return superResult } - fun addAccessorToClass(accessor: AccessorForCallableDescriptor<*>, irClassToAddAccessor: IrClass, typeMapper: KotlinTypeMapper) { + private fun accessorToIrAccessor(isConstructor: Boolean, accessor: CallableMemberDescriptor, context: JvmBackendContext, descriptor: FunctionDescriptor, accessorOwner: ClassOrPackageFragmentDescriptor): FunctionDescriptor { + return if (isConstructor) + (accessor as AccessorForConstructorDescriptor).constructorDescriptorWithMarker( + context.ir.symbols.defaultConstructorMarker.descriptor.defaultType + ) + else descriptor.toStatic(accessorOwner, Name.identifier(context.state.typeMapper.mapAsmMethod(accessor as FunctionDescriptor).name)) + } + + fun addAccessorToClass(accessor: AccessorForCallableDescriptor<*>, irClassToAddAccessor: IrClass, context: JvmBackendContext) { val accessorOwner = (accessor as FunctionDescriptor).containingDeclaration as ClassOrPackageFragmentDescriptor val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) - val accessorDescriptor = accessor.toStatic(accessorOwner, Name.identifier(typeMapper.mapAsmMethod(accessor).name)) + val isConstructor = accessor.calleeDescriptor is ConstructorDescriptor + val accessorForIr = accessorToIrAccessor(isConstructor, accessor, context, accessor.calleeDescriptor as FunctionDescriptor, accessorOwner) val syntheticFunction = IrFunctionImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, - accessorDescriptor, body + accessorForIr, body ) val calleeDescriptor = accessor.calleeDescriptor as FunctionDescriptor - val returnExpr = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, calleeDescriptor) - Companion.copyAllArgsToValueParams(returnExpr, accessorDescriptor) - body.statements.add(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor, returnExpr)) + val delegationCall = + if (!isConstructor) + IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, calleeDescriptor) + else IrDelegatingConstructorCallImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + createFunctionSymbol(accessor.calleeDescriptor) as IrConstructorSymbol, + accessor.calleeDescriptor as ClassConstructorDescriptor + ) + copyAllArgsToValueParams(delegationCall, accessorForIr) + + body.statements.add(if (isConstructor) delegationCall else IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor, delegationCall)) irClassToAddAccessor.declarations.add(syntheticFunction) } @@ -193,7 +229,7 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, return calculatedAccessor } - private fun copyAllArgsToValueParams(call: IrCallImpl, fromDescriptor: CallableMemberDescriptor) { + private fun copyAllArgsToValueParams(call: IrMemberAccessExpression, fromDescriptor: CallableMemberDescriptor) { var offset = 0 val newDescriptor = call.descriptor newDescriptor.dispatchReceiverParameter?.let { @@ -208,5 +244,18 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, fromDescriptor.valueParameters[i + offset])) } } + + private fun AccessorForConstructorDescriptor.constructorDescriptorWithMarker(marker: KotlinType) = + ClassConstructorDescriptorImpl.createSynthesized(containingDeclaration, annotations, false, source).also { + it.initialize( + DescriptorUtils.getReceiverParameterType(extensionReceiverParameter), + dispatchReceiverParameter, + emptyList()/*TODO*/, + calleeDescriptor.valueParameters.map { it.copy(this, it.name, it.index) } + ValueParameterDescriptorImpl.createWithDestructuringDeclarations(it, null, calleeDescriptor.valueParameters.size, Annotations.EMPTY, Name.identifier("marker"), marker, false, false, false, null, SourceElement.NO_SOURCE, null), + calleeDescriptor.returnType, + Modality.FINAL, + Visibilities.LOCAL + ) + } } } \ No newline at end of file