From 99d32e0b8de34761e8d9c756d882febdcdc7877b Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 7 Nov 2018 18:32:24 +0300 Subject: [PATCH] Compiler symbolization part 3 --- .../jetbrains/kotlin/backend/konan/Boxing.kt | 160 ++- .../jetbrains/kotlin/backend/konan/Context.kt | 186 +-- .../konan/EnumSpecialDescriptorsFactory.kt | 182 ++- .../kotlin/backend/konan/KonanLower.kt | 21 +- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 36 +- .../kotlin/backend/konan/lower/Autoboxing.kt | 56 +- .../backend/konan/lower/BridgesBuilding.kt | 80 +- .../konan/lower/CallableReferenceLowering.kt | 393 +++--- .../konan/lower/DataClassOperatorsLowering.kt | 9 +- .../lower/DeepCopyIrTreeWithDescriptors.kt | 4 +- .../backend/konan/lower/DelegationLowering.kt | 113 +- .../backend/konan/lower/EnumClassLowering.kt | 442 ++++--- .../backend/konan/lower/EnumWhenLowering.kt | 40 +- .../konan/lower/FinallyBlocksLowering.kt | 79 +- .../backend/konan/lower/FunctionInlining.kt | 3 +- .../konan/lower/InitializersLowering.kt | 106 +- .../backend/konan/lower/InnerClassLowering.kt | 43 +- .../backend/konan/lower/LateinitLowering.kt | 71 +- .../konan/lower/ReturnsInsertionLowering.kt | 9 +- .../konan/lower/SharedVariablesLowering.kt | 127 -- .../konan/lower/SuspendFunctionsLowering.kt | 1074 ++++++++--------- .../backend/konan/lower/TestProcessor.kt | 536 ++++---- .../backend/konan/lower/VarargLowering.kt | 77 +- .../konan/lower/loops/HeaderProcessor.kt | 1 - .../serialization/BackingFieldVisitor.kt | 2 +- .../org/jetbrains/kotlin/ir/util/IrUtils2.kt | 394 +++--- 26 files changed, 1756 insertions(+), 2488 deletions(-) delete mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt index f942546729a..dea42b68383 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt @@ -6,16 +6,13 @@ package org.jetbrains.kotlin.backend.konan import llvm.* +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe import org.jetbrains.kotlin.backend.konan.llvm.* -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction @@ -23,8 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.name.Name @@ -67,52 +65,41 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la val parameterType = unboxedType val returnType = boxedType - val descriptor = SimpleFunctionDescriptorImpl.create( - inlinedClass.descriptor, - Annotations.EMPTY, - Name.special(""), - CallableMemberDescriptor.Kind.DECLARATION, - SourceElement.NO_SOURCE - ) - - val parameter = ValueParameterDescriptorImpl( - descriptor, - null, - 0, - Annotations.EMPTY, - Name.identifier("value"), - parameterType.toKotlinType(), - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) - - descriptor.initialize( - null, - null, - emptyList(), - listOf(parameter), - returnType.toKotlinType(), - Modality.FINAL, - Visibilities.PUBLIC - ) - val startOffset = inlinedClass.startOffset val endOffset = inlinedClass.endOffset - IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply { - this.valueParameters.add(IrValueParameterImpl( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - parameter, - parameterType, - null - )) - - this.parent = inlinedClass + val descriptor = WrappedSimpleFunctionDescriptor() + IrFunctionImpl( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(descriptor), + Name.special(""), + Visibilities.PUBLIC, + Modality.FINAL, + returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { function -> + function.valueParameters.add(WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + IrValueParameterSymbolImpl(it), + Name.identifier("value"), + index = 0, + varargElementType = null, + isCrossinline = false, + type = parameterType, + isNoinline = false + ).apply { + it.bind(this) + parent = function + } + }) + descriptor.bind(function) + function.parent = inlinedClass } } @@ -128,52 +115,41 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context. val parameterType = boxedType val returnType = unboxedType - val descriptor = SimpleFunctionDescriptorImpl.create( - inlinedClass.descriptor, - Annotations.EMPTY, - Name.special(""), - CallableMemberDescriptor.Kind.DECLARATION, - SourceElement.NO_SOURCE - ) - - val parameter = ValueParameterDescriptorImpl( - descriptor, - null, - 0, - Annotations.EMPTY, - Name.identifier("value"), - parameterType.toKotlinType(), - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) - - descriptor.initialize( - null, - null, - emptyList(), - listOf(parameter), - returnType.toKotlinType(), - Modality.FINAL, - Visibilities.PUBLIC - ) - val startOffset = inlinedClass.startOffset val endOffset = inlinedClass.endOffset - IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply { - this.valueParameters.add(IrValueParameterImpl( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - parameter, - parameterType, - null - )) - - this.parent = inlinedClass + val descriptor = WrappedSimpleFunctionDescriptor() + IrFunctionImpl( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(descriptor), + Name.special(""), + Visibilities.PUBLIC, + Modality.FINAL, + returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { function -> + function.valueParameters.add(WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + IrValueParameterSymbolImpl(it), + Name.identifier("value"), + index = 0, + varargElementType = null, + isCrossinline = false, + type = parameterType, + isNoinline = false + ).apply { + it.bind(this) + parent = function + } + }) + descriptor.bind(function) + function.parent = inlinedClass } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 9d1f39fd842..8386b4280fe 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.konan import llvm.LLVMDumpModule import llvm.LLVMModuleRef import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.KonanIr @@ -20,8 +22,6 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.SourceManager @@ -29,15 +29,13 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.name.FqName @@ -51,6 +49,8 @@ import org.jetbrains.kotlin.serialization.deserialization.getName import java.lang.System.out import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.reflect.KProperty +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl /** * Offset for synthetic elements created by lowerings and not attributable to other places in the source code. @@ -97,7 +97,7 @@ internal class SpecialDeclarationsFactory(val context: Context) { } fun getLoweredEnum(enumClass: IrClass): LoweredEnum { - assert(enumClass.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: ${enumClass.descriptor}" }) + assert(enumClass.kind == ClassKind.ENUM_CLASS) { "Expected enum class but was: ${enumClass.descriptor}" } return loweredEnums.getOrPut(enumClass) { enumSpecialDeclarationsFactory.createLoweredEnum(enumClass) } @@ -125,143 +125,81 @@ internal class SpecialDeclarationsFactory(val context: Context) { fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction { val irFunction = overriddenFunctionDescriptor.descriptor - assert(overriddenFunctionDescriptor.needBridge, - { "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" }) + assert(overriddenFunctionDescriptor.needBridge) { + "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" + } val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) { createBridge(irFunction, bridgeDirections) } } - private fun createBridge(function: IrFunction, bridgeDirections: BridgeDirections): IrFunctionImpl { + private fun createBridge(function: IrSimpleFunction, + bridgeDirections: BridgeDirections) = WrappedSimpleFunctionDescriptor().let { descriptor -> + val startOffset = function.startOffset + val endOffset = function.endOffset val returnType = when (bridgeDirections.array[0]) { BridgeDirection.TO_VALUE_TYPE, BridgeDirection.NOT_NEEDED -> function.returnType BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType } - - val dispatchReceiver = when (bridgeDirections.array[1]) { - BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!! - BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter - BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!! - } - - val extensionReceiverType = when (bridgeDirections.array[2]) { - BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!.type - BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter?.type - BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType - } - - val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter -> - when (bridgeDirections.array[index + 3]) { - BridgeDirection.TO_VALUE_TYPE -> valueParameter.type - BridgeDirection.NOT_NEEDED -> valueParameter.type - BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType - } - } - val bridgeDescriptor = createBridgeDescriptor( - function, - bridgeDirections, - returnType, - dispatchReceiver, - extensionReceiverType, - valueParameterTypes - ) - - val bridge = IrFunctionImpl( - function.startOffset, - function.endOffset, + IrFunctionImpl( + startOffset, endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD(function), - bridgeDescriptor, - returnType + IrSimpleFunctionSymbolImpl(descriptor), + "${function.functionName}".synthesizedName, + function.visibility, + function.modality, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = function.isSuspend, + returnType = returnType ).apply { - this.parent = function.parent - } + descriptor.bind(this) + parent = function.parent - bridge.dispatchReceiverParameter = dispatchReceiver?.let { - IrValueParameterImpl( - it.startOffset, - it.endOffset, - IrDeclarationOrigin.DEFINED, - it.descriptor, - it.type, - null - ) - } + val dispatchReceiver = when (bridgeDirections.array[1]) { + BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!! + BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter + BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!! + } - extensionReceiverType?.let { - val extensionReceiverParameter = function.extensionReceiverParameter!! - bridge.extensionReceiverParameter = IrValueParameterImpl( - extensionReceiverParameter.startOffset, - extensionReceiverParameter.endOffset, - extensionReceiverParameter.origin, - bridge.descriptor.extensionReceiverParameter!!, - it, null - ) - } - function.valueParameters.mapIndexedTo(bridge.valueParameters) { index, valueParameter -> - val type = valueParameterTypes[index] + val extensionReceiver = when (bridgeDirections.array[2]) { + BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!! + BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter + BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!! + } - IrValueParameterImpl( - valueParameter.startOffset, - valueParameter.endOffset, - valueParameter.origin, - bridge.descriptor.valueParameters[index], - type, valueParameter.varargElementType - ) - } + val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter -> + when (bridgeDirections.array[index + 3]) { + BridgeDirection.TO_VALUE_TYPE -> valueParameter.type + BridgeDirection.NOT_NEEDED -> valueParameter.type + BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType + } + } - function.typeParameters.mapTo(bridge.typeParameters) { - IrTypeParameterImpl(it.startOffset, it.endOffset, it.origin, it.descriptor).apply { - superTypes += it.superTypes + dispatchReceiverParameter = dispatchReceiver?.copyTo(this) + extensionReceiverParameter = extensionReceiver?.copyTo(this) + function.valueParameters.mapTo(valueParameters) { it.copyTo(this, type = valueParameterTypes[it.index]) } + + function.typeParameters.mapIndexedTo(typeParameters) { index, parameter -> + WrappedTypeParameterDescriptor().let { + IrTypeParameterImpl( + startOffset, endOffset, + origin, + IrTypeParameterSymbolImpl(it), + parameter.name, + index, + parameter.isReified, + parameter.variance + ).apply { + it.bind(this) + superTypes += parameter.superTypes + } + } } } - - return bridge - } - - private fun createBridgeDescriptor( - function: IrFunction, - bridgeDirections: BridgeDirections, - returnType: IrType, - dispatchReceiverParameter: IrValueParameter?, - extensionReceiverType: IrType?, - valueParameterTypes: List - ): SimpleFunctionDescriptor { - - val descriptor = function.descriptor - val bridgeDescriptor = SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ descriptor.containingDeclaration, - /* annotations = */ Annotations.EMPTY, - /* name = */ "${function.functionName}".synthesizedName, - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE) - - val valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor -> - ValueParameterDescriptorImpl( - containingDeclaration = valueParameterDescriptor.containingDeclaration, - original = null, - index = index, - annotations = Annotations.EMPTY, - name = valueParameterDescriptor.name, - outType = valueParameterTypes[index].toKotlinType(), - declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(), - isCrossinline = valueParameterDescriptor.isCrossinline, - isNoinline = valueParameterDescriptor.isNoinline, - varargElementType = valueParameterDescriptor.varargElementType, - source = SourceElement.NO_SOURCE) - } - bridgeDescriptor.initialize( - /* receiverParameterType = */ extensionReceiverType?.toKotlinType(), - /* dispatchReceiverParameter = */ dispatchReceiverParameter?.descriptor as ReceiverParameterDescriptor?, - /* typeParameters = */ descriptor.typeParameters, - /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ returnType.toKotlinType(), - /* modality = */ descriptor.modality, - /* visibility = */ descriptor.visibility).apply { - isSuspend = descriptor.isSuspend - } - return bridgeDescriptor } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt index ca99b3a1c71..fa165e73112 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt @@ -5,143 +5,123 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName -import org.jetbrains.kotlin.backend.konan.descriptors.enumEntries -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.* +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver -import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.* -internal object DECLARATION_ORIGIN_ENUM : - IrDeclarationOriginImpl("ENUM") +internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM") internal data class LoweredEnum(val implObject: IrClass, val valuesField: IrField, val valuesGetter: IrSimpleFunction, val itemGetterSymbol: IrSimpleFunctionSymbol, - val itemGetterDescriptor: FunctionDescriptor, val entriesMap: Map) internal class EnumSpecialDeclarationsFactory(val context: Context) { - fun createLoweredEnum(enumClass: IrClass): LoweredEnum { - val enumClassDescriptor = enumClass.descriptor + private val symbols = context.ir.symbols + fun createLoweredEnum(enumClass: IrClass): LoweredEnum { val startOffset = enumClass.startOffset val endOffset = enumClass.endOffset - val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL, - ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) - - val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply { - createParameterDeclarations() + val implObject = WrappedClassDescriptor().let { + IrClassImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrClassSymbolImpl(it), + "OBJECT".synthesizedName, + ClassKind.OBJECT, + Visibilities.PUBLIC, + Modality.FINAL, + isCompanion = false, + isInner = false, + isData = false, + isExternal = false, + isInline = false + ).apply { + it.bind(this) + parent = enumClass + createParameterDeclarations() + } } - val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor) - val valuesType = context.ir.symbols.array.typeWith(enumClass.defaultType) - val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty, valuesType) - - val valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor) - val valuesGetter = IrFunctionImpl( - startOffset, endOffset, - DECLARATION_ORIGIN_ENUM, - valuesGetterDescriptor, - valuesType - ).also { - it.parent = implObject - it.createDispatchReceiverParameter() + val valuesType = symbols.array.typeWith(enumClass.defaultType) + val valuesField = WrappedFieldDescriptor().let { + IrFieldImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrFieldSymbolImpl(it), + "VALUES".synthesizedName, + valuesType, + Visibilities.PRIVATE, + isFinal = true, + isExternal = false, + isStatic = false + ).apply { + it.bind(this) + parent = implObject + } } - val memberScope = MemberScope.Empty + val valuesGetter = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrSimpleFunctionSymbolImpl(it), + "get-VALUES".synthesizedName, + Visibilities.PUBLIC, + Modality.FINAL, + valuesType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + it.bind(this) + parent = implObject + } + } val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first() - // TODO: why primary? - val constructor = implObject.addSimpleDelegatingConstructor( + implObject.addSimpleDelegatingConstructor( constructorOfAny, context.irBuiltIns, - DECLARATION_ORIGIN_ENUM, - true + true // TODO: why primary? ) - val constructorDescriptor = constructor.descriptor - implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor) - implObject.setSuperSymbolsAndAddFakeOverrides(listOf(context.irBuiltIns.anyType)) - implObject.parent = enumClass - valuesField.parent = implObject + implObject.superTypes += context.irBuiltIns.anyType + implObject.addFakeOverrides() - val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor) + val itemGetterSymbol = symbols.array.functions.single { it.descriptor.name == Name.identifier("get") } + val enumEntriesMap = enumClass.declarations + .filterIsInstance() + .sortedBy { it.name } + .withIndex() + .associate { it.value.name to it.index } + .toMap() return LoweredEnum( implObject, valuesField, valuesGetter, - itemGetterSymbol, itemGetterDescriptor, - createEnumEntriesMap(enumClassDescriptor)) + itemGetterSymbol, + enumEntriesMap) } - - private fun createValuesGetterDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor) - : FunctionDescriptor { - val returnType = genericArrayType.defaultType.replace(listOf(TypeProjectionImpl(enumClassDescriptor.defaultType))) - val result = SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ implObjectDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ "get-VALUES".synthesizedName, - /* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED, - /* source = */ SourceElement.NO_SOURCE) - result.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ null, - /* typeParameters = */ listOf(), - /* unsubstitutedValueParameters = */ listOf(), - /* unsubstitutedReturnType = */ returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PUBLIC) - return result - } - - private fun createEnumValuesField(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor): PropertyDescriptor { - val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, enumClassDescriptor.defaultType) - val receiver = ReceiverParameterDescriptorImpl( - implObjectDescriptor, - ImplicitClassReceiver(implObjectDescriptor, null), - Annotations.EMPTY - ) - return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, - false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, - false, false, false, false, false, false).apply { - - this.setType(valuesArrayType, emptyList(), receiver, null) - this.initialize(null, null) - } - } - - private val genericArrayType = context.ir.symbols.array.descriptor - - private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair { - val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") } - - val typeParameterT = genericArrayType.declaredTypeParameters[0] - val enumClassType = enumClassDescriptor.defaultType - val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType))) - return getter to getter.descriptor.substitute(typeSubstitutor)!! - } - - private fun createEnumEntriesMap(enumClassDescriptor: ClassDescriptor): Map { - val map = mutableMapOf() - enumClassDescriptor.enumEntries - .sortedBy { it.name } - .forEachIndexed { index, entry -> map.put(entry.name, index) } - return map - } - } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 8feb85c96e3..7bc570b5f92 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering -import org.jetbrains.kotlin.backend.konan.lower.SharedVariablesLowering import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.ir.declarations.IrFile @@ -65,10 +64,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) irModule.files.forEach(InteropLoweringPart1(context)::lower) } - phaser.phase(KonanPhase.LOWER_LATEINIT) { - irModule.files.forEach(LateinitLowering(context)::lower) - } - val symbolTable = context.ir.symbols.symbolTable do { @@ -82,6 +77,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) } private fun lowerFile(irFile: IrFile, phaser: PhaseManager) { + phaser.phase(KonanPhase.LOWER_LATEINIT) { + LateinitLowering(context).lower(irFile) + } phaser.phase(KonanPhase.LOWER_STRING_CONCAT) { StringConcatenationLowering(context).lower(irFile) } @@ -94,13 +92,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) phaser.phase(KonanPhase.LOWER_ENUMS) { EnumClassLowering(context).run(irFile) } - - /** - * TODO: this is workaround for issue of unitialized parents in IrDeclaration, - * the last one detected in [EnumClassLowering]. The issue appears in [DefaultArgumentStubGenerator]. - */ - irFile.patchDeclarationParents() - phaser.phase(KonanPhase.LOWER_INITIALIZERS) { InitializersLowering(context).runOnFilePostfix(irFile) } @@ -113,12 +104,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) phaser.phase(KonanPhase.LOWER_CALLABLES) { CallableReferenceLowering(context).lower(irFile) } - - /** - * TODO: this is workaround for issue of unitialized parents in IrDeclaration, - * the last one detected in [CallableReferenceLowering]. The issue appears in [LocalDeclarationsLowering]. - */ - irFile.patchDeclarationParents() phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { LocalDeclarationsLowering(context).runOnFilePostfix(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 8498f51aecb..e161ec006c4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint import org.jetbrains.kotlin.backend.konan.lower.TestProcessor import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.UnsignedType -import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName import org.jetbrains.kotlin.config.coroutinesPackageFqName import org.jetbrains.kotlin.config.languageVersionSettings @@ -370,6 +369,9 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val getContinuation = symbolTable.referenceSimpleFunction( context.getInternalFunctions("getContinuation").single()) + val returnIfSuspended = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("returnIfSuspended").single()) + val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction( context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single()) @@ -435,10 +437,14 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val } && !it.isExpect } - val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!! + val isInitializedGetter = symbolTable.referenceSimpleFunction(isInitializedPropertyDescriptor.getter!!) val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl) + val kMutableProperty0 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0) + val kMutableProperty1 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1) + val kMutableProperty2 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2) + val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl) val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl) val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl) @@ -502,32 +508,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val topLevelSuite = getKonanTestClass("TopLevelSuite") val testFunctionKind = getKonanTestClass("TestFunctionKind") - val baseClassSuiteConstructor = baseClassSuite.descriptor.constructors.single { - it.valueParameters.size == 2 && - KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String - KotlinBuiltIns.isBoolean(it.valueParameters[1].type) // ignored: Boolean - } - - val topLevelSuiteConstructor = symbolTable.referenceConstructor(topLevelSuite.descriptor.constructors.single { - it.valueParameters.size == 1 && - KotlinBuiltIns.isString(it.valueParameters[0].type) // name: String - }) - - val topLevelSuiteRegisterFunction = - getFunction(Name.identifier("registerFunction"), topLevelSuite.descriptor.defaultType) { - it.valueParameters.size == 2 && - it.valueParameters[0].type == testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind - it.valueParameters[1].type.isFunctionType // function: () -> Unit - } - - val topLevelSuiteRegisterTestCase = - getFunction(Name.identifier("registerTestCase"), topLevelSuite.descriptor.defaultType) { - it.valueParameters.size == 3 && - KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String - it.valueParameters[1].type.isFunctionType && // function: () -> Unit - KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean - } - private val testFunctionKindCache = mutableMapOf() fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) { symbolTable.referenceEnumEntry(testFunctionKind.descriptor.unsubstitutedMemberScope.getContributedClassifier( diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt index c4faed039dc..d60f2cffe1f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.atMostOne +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.target @@ -15,9 +17,7 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull import org.jetbrains.kotlin.backend.konan.irasdescriptors.isOverridable import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSuspend -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -67,17 +68,17 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr } } - private var currentFunctionDescriptor: IrFunction? = null + private var currentFunction: IrFunction? = null override fun visitFunction(declaration: IrFunction): IrStatement { - currentFunctionDescriptor = declaration + currentFunction = declaration val result = super.visitFunction(declaration) - currentFunctionDescriptor = null + currentFunction = null return result } override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) { - is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunctionDescriptor?.symbol) { + is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunction?.symbol) { this.useAs(irBuiltIns.anyNType) } else { this.useAs(returnTarget.owner.returnType) @@ -389,6 +390,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT } (irConstructor.body as IrBlockBody).statements.forEach { statement -> + statement.setDeclarationsParent(result) +statement.transform(object : IrElementTransformerVoid() { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { expression.transformChildrenVoid() @@ -435,38 +437,22 @@ private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpl require(irConstructor.constructedClass.isInlined()) require(!irConstructor.isPrimary) - val descriptor = SimpleFunctionDescriptorImpl.create( - irConstructor.descriptor.containingDeclaration, - irConstructor.descriptor.annotations, - Name.special(""), - CallableMemberDescriptor.Kind.SYNTHESIZED, - irConstructor.descriptor.source - ) - - val parameterDescriptors = irConstructor.descriptor.valueParameters.map { - it.copy(descriptor, it.name, it.index) - } - - descriptor.initialize( - null, - null, - emptyList(), - parameterDescriptors, - irConstructor.descriptor.returnType, - Modality.FINAL, - irConstructor.visibility - ) - + val descriptor = WrappedSimpleFunctionDescriptor(irConstructor.descriptor.annotations, irConstructor.descriptor.source) IrFunctionImpl( - irConstructor.startOffset, - irConstructor.endOffset, + irConstructor.startOffset, irConstructor.endOffset, IrDeclarationOrigin.DEFINED, - descriptor, - irConstructor.returnType + IrSimpleFunctionSymbolImpl(descriptor), + Name.special(""), + irConstructor.visibility, + Modality.FINAL, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false, + returnType = irConstructor.returnType ).apply { + descriptor.bind(this) parent = irConstructor.parent - irConstructor.valueParameters.mapTo(this.valueParameters) { - it.copy(this.descriptor.valueParameters[it.index]) - } + irConstructor.valueParameters.mapTo(valueParameters) { it.copyTo(this) } } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt index 2135ba5a41a..e25522dea1b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt @@ -7,15 +7,14 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -26,6 +25,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.util.simpleFunctions @@ -64,54 +65,41 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain val job = expression.getValueArgument(3) as IrFunctionReference val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner - val jobDescriptor = job.descriptor - val arg = jobDescriptor.valueParameters[0] + if (!::runtimeJobFunction.isInitialized) { - val runtimeJobDescriptor = SimpleFunctionDescriptorImpl.create( - jobDescriptor.containingDeclaration, - jobDescriptor.annotations, - jobDescriptor.name, - jobDescriptor.kind, - jobDescriptor.source + val arg = jobFunction.valueParameters[0] + val startOffset = jobFunction.startOffset + val endOffset = jobFunction.endOffset + runtimeJobFunction = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(it), + jobFunction.name, + jobFunction.visibility, + jobFunction.modality, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false, + returnType = context.irBuiltIns.anyNType ).apply { - initialize( - null, - null, - emptyList(), - listOf(ValueParameterDescriptorImpl( - containingDeclaration = this, - original = null, - index = 0, - annotations = Annotations.EMPTY, - name = arg.name, - outType = nullableAnyType, - declaresDefaultValue = arg.declaresDefaultValue(), - isCrossinline = arg.isCrossinline, - isNoinline = arg.isNoinline, - varargElementType = arg.varargElementType, - source = arg.source - )), - nullableAnyType, - jobDescriptor.modality, - jobDescriptor.visibility - ) + it.bind(this) + } } - runtimeJobFunction = IrFunctionImpl( - jobFunction.startOffset, - jobFunction.endOffset, - IrDeclarationOrigin.DEFINED, - runtimeJobDescriptor, - context.irBuiltIns.anyNType - ).also { - it.valueParameters += IrValueParameterImpl( - it.startOffset, - it.endOffset, + runtimeJobFunction.valueParameters += WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, IrDeclarationOrigin.DEFINED, - it.descriptor.valueParameters.single(), - context.irBuiltIns.anyNType, - null - ) + IrValueParameterSymbolImpl(it), + arg.name, + arg.index, + type = context.irBuiltIns.anyNType, + varargElementType = null, + isCrossinline = arg.isCrossinline, + isNoinline = arg.isNoinline + ).apply { it.bind(this) } } } val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt index 98be4a171da..2b755b45029 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.descriptors.* +import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName @@ -15,14 +17,7 @@ import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe import org.jetbrains.kotlin.backend.konan.irasdescriptors.isFunctionOrKFunctionType import org.jetbrains.kotlin.backend.konan.llvm.functionName -import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor -import org.jetbrains.kotlin.builtins.getFunctionalClassKind 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.ClassDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* @@ -32,9 +27,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl -import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.* @@ -42,8 +36,6 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.storage.LockBasedStorageManager internal class CallableReferenceLowering(val context: Context): FileLoweringPass { @@ -108,12 +100,9 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass } val parent = allScopes.map { it.irElement }.filterIsInstance().last() - val loweredFunctionReference = FunctionReferenceBuilder( - currentScope!!.scope.scopeOwner, - parent, - expression - ).build() - val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) + val loweredFunctionReference = FunctionReferenceBuilder(parent, expression).build() + val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, + expression.startOffset, expression.endOffset) return irBuilder.irBlock(expression) { +loweredFunctionReference.functionReferenceClass +irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply { @@ -138,34 +127,64 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass private val getContinuationSymbol = symbols.getContinuation - private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor, - val parent: IrDeclarationParent, + private inner class FunctionReferenceBuilder(val parent: IrDeclarationParent, val functionReference: IrFunctionReference) { - private val functionDescriptor = functionReference.descriptor.original - private val irFunction = functionReference.symbol.owner - private val functionParameters = irFunction.explicitParameters + private val startOffset = functionReference.startOffset + private val endOffset = functionReference.endOffset + private val referencedFunction = functionReference.symbol.owner + private val functionParameters = referencedFunction.explicitParameters private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first } private val unboundFunctionParameters = functionParameters - boundFunctionParameters - private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl - private lateinit var functionReferenceClass: IrClassImpl - private lateinit var functionReferenceThis: IrValueParameterSymbol - private lateinit var argumentToPropertiesMap: Map + private val typeArgumentsMap = referencedFunction.typeParameters.associate { typeParam -> + typeParam.symbol to functionReference.getTypeArgument(typeParam.index)!! + } + + private val functionReferenceClass = WrappedClassDescriptor().let { + IrClassImpl( + startOffset,endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrClassSymbolImpl(it), + "${referencedFunction.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName, + ClassKind.CLASS, + Visibilities.PRIVATE, + Modality.FINAL, + isCompanion = false, + isInner = false, + isData = false, + isExternal = false, + isInline = false + ).apply { + it.bind(this) + parent = this@FunctionReferenceBuilder.parent + createParameterDeclarations() + } + } + + private val functionReferenceThis = functionReferenceClass.thisReceiver!! + + private val argumentToPropertiesMap = boundFunctionParameters.associate { + it to createField( + startOffset, endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + it.type, + it.name, + isMutable = false, + owner = functionReferenceClass + ) + } private val kFunctionImplSymbol = symbols.kFunctionImpl private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single() - val isKFunction = functionReference.type.classifierOrNull?.descriptor - ?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.KFunction + val isKFunction = functionReference.type.isKFunction() fun build(): BuiltFunctionReference { - val startOffset = functionReference.startOffset - val endOffset = functionReference.endOffset val superClassType = if (isKFunction) { - kFunctionImplSymbol.typeWith(irFunction.returnType) + kFunctionImplSymbol.typeWith(referencedFunction.returnType) } else { irBuiltIns.anyType } @@ -181,7 +200,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass } val functionParameterTypes = unboundFunctionParameters.map { it.type } - val functionClassTypeParameters = functionParameterTypes + irFunction.returnType + val functionClassTypeParameters = functionParameterTypes + referencedFunction.returnType superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters) var suspendFunctionIrClass: IrClass? = null @@ -190,136 +209,65 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass lastParameterType as IrSimpleType // If the last parameter is Continuation<> inherit from SuspendFunction. suspendFunctionIrClass = symbols.suspendFunctions[numberOfParameters - 1].owner - var suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + + val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + (lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType) superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters) } - functionReferenceClassDescriptor = object : ClassDescriptorImpl( - /* containingDeclaration = */ containingDeclaration, - /* name = */ "${functionDescriptor.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName, - /* modality = */ Modality.FINAL, - /* kind = */ ClassKind.CLASS, - /* superTypes = */ superTypes.map { it.toKotlinType() }, - /* source = */ SourceElement.NO_SOURCE, - /* isExternal = */ false, - /* storageManager = */ LockBasedStorageManager.NO_LOCKS - ) { - override fun getVisibility() = Visibilities.PRIVATE - } - functionReferenceClass = IrClassImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - descriptor = functionReferenceClassDescriptor - ) - functionReferenceClass.parent = this.parent + val constructor = buildConstructor() + buildInvokeMethod(functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }) + suspendFunctionIrClass?.let { buildInvokeMethod(it.simpleFunctions().single { it.name.asString() == "invoke" }) } + functionReferenceClass.superTypes += superTypes + functionReferenceClass.addFakeOverrides() - val constructorBuilder = createConstructorBuilder() - - val invokeFunctionSymbol = - functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol - val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionSymbol, functionReferenceClass) - - var suspendInvokeMethodBuilder: SymbolWithIrBuilder? = null - if (suspendFunctionIrClass != null) { - val suspendInvokeFunctionSymbol = - suspendFunctionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol - suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionSymbol, functionReferenceClass) - } - - val memberScope = stub("callable reference class") - functionReferenceClassDescriptor.initialize( - memberScope, setOf(constructorBuilder.symbol.descriptor), null) - - functionReferenceClass.createParameterDeclarations() - - functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol - - constructorBuilder.initialize() - functionReferenceClass.addChild(constructorBuilder.ir) - - invokeMethodBuilder.initialize() - functionReferenceClass.addChild(invokeMethodBuilder.ir) - - suspendInvokeMethodBuilder?.let { - it.initialize() - functionReferenceClass.addChild(it.ir) - } - - functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superTypes) - - return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir) + return BuiltFunctionReference(functionReferenceClass, constructor) } - private fun createConstructorBuilder() - = object : SymbolWithIrBuilder() { + private fun buildConstructor() = WrappedClassConstructorDescriptor().let { + IrConstructorImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrConstructorSymbolImpl(it), + Name.special(""), + Visibilities.PUBLIC, + functionReferenceClass.defaultType, + isInline = false, + isExternal = false, + isPrimary = true + ).apply { + it.bind(this) + parent = functionReferenceClass + functionReferenceClass.declarations += this - override fun buildSymbol() = IrConstructorSymbolImpl( - ClassConstructorDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* isPrimary = */ false, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl - val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter -> - parameter.descriptor.copyAsValueParameter(descriptor, index) - } - descriptor.initialize(constructorParameters, Visibilities.PUBLIC) - descriptor.returnType = functionReferenceClassDescriptor.defaultType - } - - override fun buildIr(): IrConstructor { - argumentToPropertiesMap = boundFunctionParameters.associate { - it.descriptor to buildField(it.name, it.type, false) + boundFunctionParameters.mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index, + type = parameter.type.substitute(typeArgumentsMap)) } - val startOffset = functionReference.startOffset - val endOffset = functionReference.endOffset - return IrConstructorImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = symbol, - returnType = functionReferenceClass.defaultType - ).apply { - - val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) - - boundFunctionParameters.mapIndexedTo(this.valueParameters) { index, parameter -> - parameter.copy(descriptor.valueParameters[index]) + body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody { + if (!isKFunction) + +irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single()) + else +irDelegatingConstructorCall(kFunctionImplConstructorSymbol.owner).apply { + val stringType = irBuiltIns.stringType + val name = IrConstImpl(startOffset, endOffset, stringType, + IrConstKind.String, referencedFunction.name.asString()) + putValueArgument(0, name) + val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String, + (functionReference.symbol.owner).fullName) + putValueArgument(1, fqName) + val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType, + boundFunctionParameters.isNotEmpty()) + putValueArgument(2, bound) + val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor + val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull() + putValueArgument(3, receiver) + putValueArgument(4, irKType(this@CallableReferenceLowering.context, referencedFunction.returnType)) } - - body = irBuilder.irBlockBody { - if (!isKFunction) +irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single()) - else +IrDelegatingConstructorCallImpl(startOffset, endOffset, - context.irBuiltIns.unitType, - kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor, 0).apply { - val stringType = irBuiltIns.stringType - val name = IrConstImpl(startOffset, endOffset, stringType, - IrConstKind.String, functionDescriptor.name.asString()) - putValueArgument(0, name) - val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String, - (functionReference.symbol.owner).fullName) - putValueArgument(1, fqName) - val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType, - boundFunctionParameters.isNotEmpty()) - putValueArgument(2, bound) - val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor - val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull() - putValueArgument(3, receiver) - putValueArgument(4, irKType(this@CallableReferenceLowering.context, irFunction.returnType)) - } - +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType) - // Save all arguments to fields. - boundFunctionParameters.forEachIndexed { index, parameter -> - +irSetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter.descriptor]!!, irGet(valueParameters[index])) - } + +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType) + // Save all arguments to fields. + boundFunctionParameters.forEachIndexed { index, parameter -> + +irSetField(irGet(functionReferenceThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index])) } } } @@ -328,108 +276,65 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass private val IrFunction.fullName: String get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString() - private fun createInvokeMethodBuilder(superFunctionSymbol: IrSimpleFunctionSymbol, parent: IrClass) - = object : SymbolWithIrBuilder() { + private fun buildInvokeMethod(superFunction: IrSimpleFunction) = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + IrSimpleFunctionSymbolImpl(it), + superFunction.name, + Visibilities.PRIVATE, + Modality.FINAL, + referencedFunction.returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = superFunction.isSuspend + ).apply { + it.bind(this) + val function = this + parent = functionReferenceClass + functionReferenceClass.declarations += function - val superFunctionDescriptor: FunctionDescriptor = superFunctionSymbol.descriptor + this.createDispatchReceiverParameter() - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ functionReferenceClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("invoke"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - val valueParameters = superFunctionDescriptor.valueParameters - .map { it.copyAsValueParameter(descriptor, it.index) } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ superFunctionDescriptor.returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PRIVATE).apply { - overriddenDescriptors += superFunctionDescriptor - isSuspend = superFunctionDescriptor.isSuspend + superFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index, + type = parameter.type.substitute(typeArgumentsMap)) } - } - override fun buildIr(): IrSimpleFunction { - val startOffset = functionReference.startOffset - val endOffset = functionReference.endOffset - val ourSymbol = symbol - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = ourSymbol, - returnType = superFunctionSymbol.owner.returnType // FIXME: substitute - ).apply { + overriddenSymbols += superFunction.symbol - val function = this - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - - this.parent = parent - - this.createDispatchReceiverParameter() - - superFunctionSymbol.owner.valueParameters.mapTo(this.valueParameters) { - it.copy(descriptor.valueParameters[it.index]) // FIXME: substitute - } - - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - irCall(functionReference.symbol).apply { - var unboundIndex = 0 - val unboundArgsSet = unboundFunctionParameters.toSet() - functionParameters.forEach { - val argument = - if (!unboundArgsSet.contains(it)) - // Bound parameter - read from field. - irGetField( - irGet(function.dispatchReceiverParameter!!), - argumentToPropertiesMap[it.descriptor]!! - ) - else { - if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) - // For suspend functions the last argument is continuation and it is implicit. - irCall(getContinuationSymbol.owner, - listOf(returnType)) - else - irGet(valueParameters[unboundIndex++]) - } - when (it) { - irFunction.dispatchReceiverParameter -> dispatchReceiver = argument - irFunction.extensionReceiverParameter -> extensionReceiver = argument - else -> putValueArgument(it.index, argument) - } + body = context.createIrBuilder(function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset) { + +irReturn( + irCall(functionReference.symbol).apply { + var unboundIndex = 0 + val unboundArgsSet = unboundFunctionParameters.toSet() + for (parameter in functionParameters) { + val argument = + if (!unboundArgsSet.contains(parameter)) + // Bound parameter - read from field. + irGetField( + irGet(function.dispatchReceiverParameter!!), + argumentToPropertiesMap[parameter]!! + ) + else { + if (function.isSuspend && unboundIndex == valueParameters.size) + // For suspend functions the last argument is continuation and it is implicit. + irCall(getContinuationSymbol.owner, listOf(returnType)) + else + irGet(valueParameters[unboundIndex++]) + } + when (parameter) { + referencedFunction.dispatchReceiverParameter -> dispatchReceiver = argument + referencedFunction.extensionReceiverParameter -> extensionReceiver = argument + else -> putValueArgument(parameter.index, argument) } - assert(unboundIndex == valueParameters.size, { "Not all arguments of are used" }) } - ) - } + assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } + } + ) } } } - - private fun buildField(name: Name, type: IrType, isMutable: Boolean): IrField = createField( - functionReference.startOffset, - functionReference.endOffset, - type, - name, - isMutable, - DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - functionReferenceClassDescriptor - ).also { - functionReferenceClass.addChild(it) - } } -} - +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt index 7da65651fc7..da3b1ca4270 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt @@ -57,12 +57,11 @@ internal class DataClassOperatorsLowering(val context: Context): FunctionLowerin extensionReceiver = argument } } else { - val tmp = scope.createTemporaryVariable(argument) - val call = irCall(newCallee, typeArguments).apply { - extensionReceiver = irGet(tmp) - } irBlock(argument) { - +tmp + val tmp = irTemporary(argument) + val call = irCall(newCallee, typeArguments).apply { + extensionReceiver = irGet(tmp) + } +irIfThenElse(call.type, irEqeqeq(irGet(tmp), irNull()), if (isToString) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt index 6b81750d918..ee21352bc29 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt @@ -71,7 +71,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, } override fun visitField(declaration: IrField) { - (declaration.descriptor as WrappedPropertyDescriptor).bind(declaration) + (declaration.descriptor as WrappedFieldDescriptor).bind(declaration) declaration.acceptChildrenVoid(this) } @@ -130,7 +130,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, WrappedClassDescriptor(descriptor.annotations, descriptor.source) override fun remapDeclaredField(descriptor: PropertyDescriptor) = - WrappedPropertyDescriptor(descriptor.annotations, descriptor.source) + WrappedFieldDescriptor(descriptor.annotations, descriptor.source) override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) = WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt index a2234cb08c6..8598b8d2b59 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.konan.Context @@ -19,7 +20,6 @@ import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl @@ -33,19 +33,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.SimpleType -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.types.replace internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { private var tempIndex = 0 @@ -59,7 +55,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa val classSymbol = if (isLocal) { - assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" }) + assert(receiverTypes.isEmpty()) { "Local delegated property cannot have explicit receiver" } when { isMutable -> symbols.kLocalDelegatedMutablePropertyImpl else -> symbols.kLocalDelegatedPropertyImpl @@ -87,29 +83,37 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa return classSymbol.constructors.single() to arguments } - private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType { - return this.defaultType.replace(type.map(::TypeProjectionImpl)) - } - override fun lower(irFile: IrFile) { val kProperties = mutableMapOf>() val arrayClass = context.ir.symbols.array.owner - val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") } + val arrayItemGetter = arrayClass.functions.single { it.name == Name.identifier("get") } val anyType = context.irBuiltIns.anyType val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType) val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType) - val kPropertiesField = IrFieldImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, - createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, - kPropertiesFieldType.toKotlinType() - ), - kPropertiesFieldType - ) + val kPropertiesField = WrappedFieldDescriptor( + Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType, + emptyMap(), SourceElement.NO_SOURCE))) + ).let { + IrFieldImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, + IrFieldSymbolImpl(it), + "KPROPERTIES".synthesizedName, + kPropertiesFieldType, + Visibilities.PRIVATE, + isFinal = true, + isExternal = false, + isStatic = true + ).apply { + it.bind(this) + parent = irFile + } + } irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { @@ -135,18 +139,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset) irBuilder.run { val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null } - if (receiversCount == 1) // Has receiver. - return createKProperty(expression, this) - else if (receiversCount == 2) - throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}") - else { // Cache KProperties with no arguments. - val field = kProperties.getOrPut(expression.descriptor) { - createKProperty(expression, this) to kProperties.size - } + return when (receiversCount) { + 1 -> createKProperty(expression, this) // Has receiver. - return irCall(arrayItemGetter).apply { - dispatchReceiver = irGetField(null, kPropertiesField) - putValueArgument(0, irInt(field.second)) + 2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}") + + else -> { // Cache KProperties with no arguments. + val field = kProperties.getOrPut(expression.descriptor) { + createKProperty(expression, this) to kProperties.size + } + + irCall(arrayItemGetter).apply { + dispatchReceiver = irGetField(null, kPropertiesField) + putValueArgument(0, irInt(field.second)) + } } } } @@ -188,11 +194,8 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa // TODO: move to object for lazy initialization. irFile.declarations.add(0, kPropertiesField.apply { initializer = IrExpressionBodyImpl(startOffset, endOffset, - context.createArrayOfExpression(kPropertyImplType, initializers, - startOffset, endOffset)) + context.createArrayOfExpression(startOffset, endOffset, kPropertyImplType, initializers)) }) - - kPropertiesField.parent = irFile } } @@ -235,15 +238,18 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa type = getterKFunctionType, symbol = expression.getter!!, descriptor = getter.descriptor, - typeArgumentsCount = 0 + typeArgumentsCount = getter.typeParameters.size, + valueArgumentsCount = getter.valueParameters.size ).apply { this.dispatchReceiver = dispatchReceiver?.let { irGet(it) } this.extensionReceiver = extensionReceiver?.let { irGet(it) } + for (index in 0 until expression.typeArgumentsCount) + putTypeArgument(index, expression.getTypeArgument(index)) } } - val setterCallableReference = expression.setter?.owner?.let { - if (!isKMutablePropertyType(expression.type.toKotlinType())) null + val setterCallableReference = expression.setter?.owner?.let { setter -> + if (!isKMutablePropertyType(expression.type)) null else { val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType( context.irBuiltIns.unitType, @@ -254,11 +260,14 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa endOffset = endOffset, type = setterKFunctionType, symbol = expression.setter!!, - descriptor = it.descriptor, - typeArgumentsCount = 0 + descriptor = setter.descriptor, + typeArgumentsCount = setter.typeParameters.size, + valueArgumentsCount = setter.valueParameters.size ).apply { this.dispatchReceiver = dispatchReceiver?.let { irGet(it) } this.extensionReceiver = extensionReceiver?.let { irGet(it) } + for (index in 0 until expression.typeArgumentsCount) + putTypeArgument(index, expression.getTypeArgument(index)) } } } @@ -297,32 +306,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } } - private fun isKMutablePropertyType(type: KotlinType): Boolean { - val arguments = type.arguments - val expectedClassDescriptor = when (arguments.size) { + private fun isKMutablePropertyType(type: IrType): Boolean { + if (type !is IrSimpleType) return false + val expectedClass = when (type.arguments.size) { 0 -> return false - 1 -> context.reflectionTypes.kMutableProperty0 - 2 -> context.reflectionTypes.kMutableProperty1 - 3 -> context.reflectionTypes.kMutableProperty2 + 1 -> context.ir.symbols.kMutableProperty0 + 2 -> context.ir.symbols.kMutableProperty1 + 3 -> context.ir.symbols.kMutableProperty2 else -> throw AssertionError("More than 2 receivers is not allowed") } - return type == expectedClassDescriptor.defaultType.replace(arguments) + return type.classifier == expectedClass } private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION : IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION") - - private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: KotlinType): PropertyDescriptorImpl { - return PropertyDescriptorImpl.create(containingDeclaration, - Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType, - emptyMap(), SourceElement.NO_SOURCE))), Modality.FINAL, Visibilities.PRIVATE, - false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, - false, false, false, false, false, false).apply { - - this.setType(fieldType, emptyList(), null, null) - this.initialize(null, null) - } - } } internal fun IrBuilderWithScope.irKType(context: KonanBackendContext, type: IrType): IrExpression { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index f7452754ccd..aec81215b89 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -8,7 +8,11 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.deepCopyWithVariables +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor +import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.runOnFilePostfix @@ -17,8 +21,6 @@ import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -28,14 +30,17 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERIN import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.storage.LockBasedStorageManager internal class EnumSyntheticFunctionsBuilder(val context: Context) { fun buildValuesExpression(startOffset: Int, endOffset: Int, @@ -105,9 +110,7 @@ internal class EnumUsageLowering(val context: Context) override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) - val descriptor = expression.descriptor as? FunctionDescriptor - ?: return expression - if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor) + if (expression.symbol != enumValuesSymbol && expression.symbol != enumValueOfSymbol) return expression val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol @@ -119,19 +122,17 @@ internal class EnumUsageLowering(val context: Context) assert (irClass.kind == ClassKind.ENUM_CLASS) - return if (descriptor.original == enumValuesDescriptor) { - enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass) - } else { - val value = expression.getValueArgument(0)!! - enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value) - } + return if (expression.symbol == enumValuesSymbol) { + enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass) + } else { + val value = expression.getValueArgument(0)!! + enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value) + } } private val enumValueOfSymbol = context.ir.symbols.enumValueOf - private val enumValueOfDescriptor = enumValueOfSymbol.descriptor private val enumValuesSymbol = context.ir.symbols.enumValues - private val enumValuesDescriptor = enumValuesSymbol.descriptor private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression { val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass) @@ -154,8 +155,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } override fun lower(irClass: IrClass) { - val descriptor = irClass.descriptor - if (descriptor.kind != ClassKind.ENUM_CLASS) return + if (irClass.kind != ClassKind.ENUM_CLASS) return EnumClassTransformer(irClass).run() } @@ -166,10 +166,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { private inner class EnumClassTransformer(val irClass: IrClass) { private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass) - private val loweredEnumConstructors = mutableMapOf() - private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf() - private val defaultEnumEntryConstructors = mutableMapOf() - private val loweredEnumConstructorParameters = mutableMapOf() + private val loweredEnumConstructors = mutableMapOf() + private val defaultEnumEntryConstructors = mutableMapOf() + private val loweredEnumConstructorParameters = mutableMapOf() private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context) fun run() { @@ -177,9 +176,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { lowerEnumConstructors(irClass) lowerEnumEntriesClasses() val defaultClass = createDefaultClassForEnumEntries() - lowerEnumClassBody() - if (defaultClass != null) - irClass.addChild(defaultClass) + lowerEnumClassBody(defaultClass) createImplObject() } @@ -225,48 +222,44 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } private fun createDefaultClassForEnumEntries(): IrClass? { - if (!irClass.declarations.any({ it is IrEnumEntry && it.correspondingClass == null })) return null - val startOffset = irClass.startOffset - val endOffset = irClass.endOffset - val descriptor = irClass.descriptor - val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL, - ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) - val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor) - defaultClass.createParameterDeclarations() - - - val constructors = mutableSetOf() - - descriptor.constructors.forEach { - val loweredEnumIrConstructor = loweredEnumConstructors[it]!! - val loweredEnumConstructor = loweredEnumIrConstructor.descriptor - - val constructor = defaultClass.addSimpleDelegatingConstructor( - loweredEnumIrConstructor, - context.irBuiltIns, - DECLARATION_ORIGIN_ENUM - ) - - val constructorDescriptor = constructor.descriptor - constructors.add(constructorDescriptor) - defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor) - - val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor] - if (irConstructor != null) { - it.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument -> - val loweredArgument = loweredEnumConstructor.valueParameters[argument.loweredIndex()] - val body = irConstructor.getDefault(loweredArgument)!!.deepCopyWithVariables() - body.transformChildrenVoid(ParameterMapper(constructor)) - body.accept(SetDeclarationsParentVisitor, constructor) - constructor.putDefault(constructorDescriptor.valueParameters[loweredArgument.index], body) - } + if (!irClass.declarations.any { it is IrEnumEntry && it.correspondingClass == null }) return null + val defaultClass = WrappedClassDescriptor().let { + IrClassImpl( + irClass.startOffset, irClass.endOffset, + DECLARATION_ORIGIN_ENUM, + IrClassSymbolImpl(it), + "DEFAULT".synthesizedName, + ClassKind.CLASS, + Visibilities.PRIVATE, + Modality.FINAL, + isCompanion = false, + isInner = false, + isData = false, + isExternal = false, + isInline = false + ).apply { + it.bind(this) + parent = irClass + irClass.declarations += this + createParameterDeclarations() } } - val memberScope = stub("enum default class") - defaultClassDescriptor.initialize(memberScope, constructors, null) + for (superConstructor in irClass.constructors) { + val constructor = defaultClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns) + defaultEnumEntryConstructors[superConstructor] = constructor - defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass.defaultType)) + for (parameter in constructor.valueParameters) { + val defaultValue = superConstructor.valueParameters[parameter.index].defaultValue ?: continue + val body = defaultValue.deepCopyWithVariables() + body.transformChildrenVoid(ParameterMapper(superConstructor, constructor, false)) + body.patchDeclarationParents(constructor) + parameter.defaultValue = body + } + } + + defaultClass.superTypes += irClass.defaultType + defaultClass.addFakeOverrides() return defaultClass } @@ -302,39 +295,42 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { ++i } - implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries)) - implObject.addChild(createValuesPropertyInitializer(enumEntries)) + implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries) + implObject.declarations += createValuesPropertyInitializer(enumEntries) - irClass.addChild(implObject) + irClass.declarations += implObject } - private val genericCreateUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance - private val genericCreateUninitializedInstanceDescriptor = genericCreateUninitializedInstanceSymbol.descriptor + private val createUninitializedInstance = context.ir.symbols.createUninitializedInstance.owner private fun createSyntheticValuesPropertyDeclaration(enumEntries: List): IrPropertyImpl { val startOffset = irClass.startOffset val endOffset = irClass.endOffset - val irValuesInitializer = context.createArrayOfExpression(irClass.defaultType, + val irValuesInitializer = context.createArrayOfExpression( + startOffset, endOffset, + irClass.defaultType, enumEntries - .sortedBy { it.descriptor.name } + .sortedBy { it.name } .map { val initializer = it.initializerExpression val entryConstructorCall = when { - initializer is IrCall -> initializer - initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> - initializer.statements.last() as IrCall - else -> error("Unexpected initializer: $initializer") - } - val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor - val entryClass = entryConstructor.constructedClass + initializer is IrCall -> initializer + + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> + initializer.statements.last() as IrCall + + else -> error("Unexpected initializer: $initializer") + } + val entryClass = (entryConstructorCall.symbol.owner as IrConstructor).constructedClass irCall(startOffset, endOffset, - genericCreateUninitializedInstanceSymbol.owner, + createUninitializedInstance, listOf(entryClass.defaultType) ) - }, startOffset, endOffset) + } + ) val irField = loweredEnum.valuesField.apply { initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer) } @@ -344,15 +340,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { val receiver = IrGetObjectValueImpl(startOffset, endOffset, loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol) val value = IrGetFieldImpl( - startOffset, - endOffset, + startOffset, endOffset, loweredEnum.valuesField.symbol, loweredEnum.valuesField.type, receiver ) val returnStatement = IrReturnImpl( - startOffset, - endOffset, + startOffset, endOffset, context.irBuiltIns.nothingType, loweredEnum.valuesGetter.symbol, value @@ -360,14 +354,14 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement)) return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, - false, loweredEnum.valuesField.descriptor, irField, getter, null).also { - it.parent = loweredEnum.implObject + false, loweredEnum.valuesField.descriptor, irField, getter, null).apply { + parent = loweredEnum.implObject } } private val initInstanceSymbol = context.ir.symbols.initInstance - private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") } + private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.owner.name == Name.identifier("get") } private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType) @@ -376,17 +370,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { val endOffset = irClass.endOffset fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = - irCall(initInstanceSymbol).apply { - putValueArgument(0, instance) - putValueArgument(1, constructor) - } + irCall(initInstanceSymbol).apply { + putValueArgument(0, instance) + putValueArgument(1, constructor) + } - return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply { - parent = irClass + val implObject = loweredEnum.implObject + return IrAnonymousInitializerImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor()) + ).apply { + parent = implObject body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { - val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!), loweredEnum.valuesField)) + val receiver = implObject.thisReceiver!! + val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField)) enumEntries - .sortedBy { it.descriptor.name } + .sortedBy { it.name } .withIndex() .forEach { val instance = irCall(arrayGetSymbol).apply { @@ -394,19 +394,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { putValueArgument(0, irInt(it.index)) } val initializer = it.value.initializerExpression!! + initializer.patchDeclarationParents(implObject) when { initializer is IrCall -> +initInstanceCall(instance, initializer) + initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { val statements = initializer.statements val constructorCall = statements.last() as IrCall statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) +initializer } + else -> error("Unexpected initializer: $initializer") } } +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { - extensionReceiver = irGet(loweredEnum.implObject.thisReceiver!!) + extensionReceiver = irGet(receiver) } } } @@ -456,85 +459,75 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor { val loweredEnumConstructor = lowerEnumConstructor(enumConstructor) - enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { - val body = enumConstructor.getDefault(it)!! - body.transformChildrenVoid(object: IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - val descriptor = expression.descriptor - when (descriptor) { - is ValueParameterDescriptor -> { - val parameter = loweredEnumConstructor.valueParameters[descriptor.loweredIndex()] - return IrGetValueImpl(expression.startOffset, - expression.endOffset, - parameter.type, - parameter.symbol) - } - } - return expression - } - }) - loweredEnumConstructor.valueParameters[it.loweredIndex()].defaultValue = body - descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor.descriptor] = loweredEnumConstructor + for (parameter in enumConstructor.valueParameters) { + val defaultValue = parameter.defaultValue ?: continue + defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true)) + loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue + defaultValue.patchDeclarationParents(loweredEnumConstructor) } - return loweredEnumConstructor - } - - private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorImpl { - val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized( - enumConstructor.descriptor.containingDeclaration, - enumConstructor.descriptor.annotations, - enumConstructor.descriptor.isPrimary, - enumConstructor.descriptor.source - ) - val valueParameters = - listOf( - loweredConstructorDescriptor.createValueParameter( - 0, - "name", - context.irBuiltIns.stringType, - enumConstructor.startOffset, - enumConstructor.endOffset - ), - loweredConstructorDescriptor.createValueParameter( - 1, - "ordinal", - context.irBuiltIns.intType, - enumConstructor.startOffset, - enumConstructor.endOffset - ) - ) + - enumConstructor.valueParameters.map { - val descriptor = it.descriptor as ValueParameterDescriptor - val loweredValueParameterDescriptor = descriptor.copy( - loweredConstructorDescriptor, - it.name, - descriptor.loweredIndex() - ) - loweredEnumConstructorParameters[descriptor] = loweredValueParameterDescriptor - it.copy(loweredValueParameterDescriptor) - } - - loweredConstructorDescriptor.initialize( - valueParameters.map { it.descriptor as ValueParameterDescriptor }, - Visibilities.PROTECTED - ) - loweredConstructorDescriptor.returnType = enumConstructor.descriptor.returnType - val loweredEnumConstructor = IrConstructorImpl( - enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin, - loweredConstructorDescriptor, - enumConstructor.returnType, - enumConstructor.body!! - ) - loweredEnumConstructor.valueParameters += valueParameters - loweredEnumConstructor.parent = enumConstructor.parent - - loweredEnumConstructors[enumConstructor.descriptor] = loweredEnumConstructor return loweredEnumConstructor } - private fun lowerEnumClassBody() { - irClass.transformChildrenVoid(EnumClassBodyTransformer()) + private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl { + val startOffset = constructor.startOffset + val endOffset = constructor.endOffset + val loweredConstructor = WrappedClassConstructorDescriptor( + constructor.descriptor.annotations, + constructor.descriptor.source + ).let { + IrConstructorImpl( + startOffset, endOffset, + constructor.origin, + IrConstructorSymbolImpl(it), + constructor.name, + Visibilities.PROTECTED, + constructor.returnType, + isInline = false, + isExternal = false, + isPrimary = constructor.isPrimary + ).apply { + it.bind(this) + parent = constructor.parent + body = constructor.body!! // Will be transformed later. + } + } + + fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) = + WrappedValueParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ENUM, + IrValueParameterSymbolImpl(it), + Name.identifier(name), + index, + type, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + it.bind(this) + parent = loweredConstructor + } + } + + loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType) + loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType) + constructor.valueParameters.mapTo(loweredConstructor.valueParameters) { + it.copyTo(loweredConstructor, index = it.loweredIndex).apply { + loweredEnumConstructorParameters[it] = this + } + } + + loweredEnumConstructors[constructor] = loweredConstructor + + return loweredConstructor + } + + private fun lowerEnumClassBody(defaultClass: IrClass?) { + irClass.transformChildrenVoid(EnumClassBodyTransformer(defaultClass)) + // Enum entries's classes have already been pulled out to the upper level - clear them up. + irClass.declarations.filterIsInstance().forEach { it.correspondingClass = null } } private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) : @@ -544,11 +537,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { val endOffset = enumConstructorCall.endOffset val origin = enumConstructorCall.origin - val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, + val result = IrDelegatingConstructorCallImpl( + startOffset, endOffset, context.irBuiltIns.unitType, - enumConstructorCall.symbol, enumConstructorCall.descriptor, enumConstructorCall.typeArgumentsCount) + enumConstructorCall.symbol) - assert(result.descriptor.valueParameters.size == 2) { + assert(result.symbol.owner.valueParameters.size == 2) { "Enum(String, Int) constructor call expected:\n${result.dump()}" } @@ -570,16 +564,18 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { - val descriptor = delegatingConstructorCall.descriptor val startOffset = delegatingConstructorCall.startOffset val endOffset = delegatingConstructorCall.endOffset - val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(descriptor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") + val delegatingConstructor = delegatingConstructorCall.symbol.owner + val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor") } - val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, - loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor, 0) + val result = IrDelegatingConstructorCallImpl( + startOffset, endOffset, + context.irBuiltIns.unitType, + loweredDelegatingConstructor.symbol) val firstParameter = enumClassConstructor.valueParameters[0] result.putValueArgument(0, @@ -588,25 +584,26 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol)) - descriptor.valueParameters.forEach { valueParameter -> - result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(valueParameter)) + delegatingConstructor.valueParameters.forEach { + result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index)) } return result } } - private abstract inner class InEnumEntry(private val enumEntry: ClassDescriptor) : EnumConstructorCallTransformer { + private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer { + override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { val name = enumEntry.name.asString() - val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry) + val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor) - val descriptor = enumConstructorCall.descriptor val startOffset = enumConstructorCall.startOffset val endOffset = enumConstructorCall.endOffset - val loweredConstructor = loweredEnumConstructors.getOrElse(descriptor) { - throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") + val enumConstructor = enumConstructorCall.symbol.owner + val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) { + throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor") } val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol) @@ -616,9 +613,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal)) - descriptor.valueParameters.forEach { valueParameter -> - val i = valueParameter.index - result.putValueArgument(i + 2, enumConstructorCall.getValueArgument(i)) + enumConstructor.valueParameters.forEach { + result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index)) } return result @@ -631,7 +627,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression } - private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { + private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { override fun createConstructorCall( startOffset: Int, endOffset: Int, @@ -640,25 +636,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { startOffset, endOffset, context.irBuiltIns.unitType, - loweredConstructor, - loweredConstructor.descriptor, - 0 + loweredConstructor ) } - private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { + private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall { - val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol + val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.owner]?.symbol ?: loweredConstructor return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol) } } - private inner class EnumClassBodyTransformer : IrElementTransformerVoid() { + private inner class EnumClassBodyTransformer(val defaultClass: IrClass?) : IrElementTransformerVoid() { private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null override fun visitClass(declaration: IrClass): IrStatement { - if (declaration.descriptor.kind == ClassKind.ENUM_CLASS) + if (declaration.kind == ClassKind.ENUM_CLASS || declaration == defaultClass) return declaration return super.visitClass(declaration) } @@ -666,27 +660,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement { assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } - enumConstructorCallTransformer = InEnumEntryInitializer(declaration.descriptor) + enumConstructorCallTransformer = InEnumEntryInitializer(declaration) - var result: IrEnumEntry = IrEnumEntryImpl(declaration.startOffset, declaration.endOffset, declaration.origin, - declaration.descriptor, null, declaration.initializerExpression) - result = super.visitEnumEntry(result) as IrEnumEntry + declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null) enumConstructorCallTransformer = null - return result + return declaration } override fun visitConstructor(declaration: IrConstructor): IrStatement { - val constructorDescriptor = declaration.descriptor - val containingClass = constructorDescriptor.containingDeclaration + val containingClass = declaration.parentAsClass // TODO local (non-enum) class in enum class constructor? val previous = enumConstructorCallTransformer if (containingClass.kind == ClassKind.ENUM_ENTRY) { assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } - enumConstructorCallTransformer = InEnumEntryClassConstructor(containingClass) + val entry = irClass.declarations.filterIsInstance().single { it.correspondingClass == containingClass } + enumConstructorCallTransformer = InEnumEntryClassConstructor(entry) } else if (containingClass.kind == ClassKind.ENUM_CLASS) { assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } enumConstructorCallTransformer = InEnumClassConstructor(declaration) @@ -703,7 +695,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { expression.transformChildrenVoid(this) val callTransformer = enumConstructorCallTransformer ?: - throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) + throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) return callTransformer.transform(expression) @@ -712,9 +704,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { expression.transformChildrenVoid(this) - if (expression.descriptor.containingDeclaration.kind == ClassKind.ENUM_CLASS) { + if (expression.symbol.owner.parentAsClass.kind == ClassKind.ENUM_CLASS) { val callTransformer = enumConstructorCallTransformer ?: - throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) + throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) return callTransformer.transform(expression) } @@ -722,34 +714,36 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { } override fun visitGetValue(expression: IrGetValue): IrExpression { - val loweredParameter = loweredEnumConstructorParameters[expression.descriptor] - if (loweredParameter != null) { - val loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!! - val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index] - assert(loweredIrParameter.descriptor == loweredParameter) - return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredIrParameter.type, - loweredIrParameter.symbol, expression.origin) + val parameter = expression.symbol.owner + val loweredParameter = loweredEnumConstructorParameters[parameter] + return if (loweredParameter == null) { + expression } else { - return expression + IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type, + loweredParameter.symbol, expression.origin) } } } } } -private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2 +private val IrValueParameter.loweredIndex: Int get() = index + 2 + +private class ParameterMapper(superConstructor: IrConstructor, + val constructor: IrConstructor, + val useLoweredIndex: Boolean) : IrElementTransformerVoid() { + private val valueParameters = superConstructor.valueParameters.toSet() -private class ParameterMapper(val originalConstructor: IrConstructor) : IrElementTransformerVoid() { override fun visitGetValue(expression: IrGetValue): IrExpression { - val descriptor = expression.descriptor - when (descriptor) { - is ValueParameterDescriptor -> { - val parameter = originalConstructor.valueParameters[descriptor.index] - return IrGetValueImpl(expression.startOffset, - expression.endOffset, - parameter.type, - parameter.symbol) - } + + val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression + if (valueParameters.contains(superParameter)) { + val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index + val parameter = constructor.valueParameters[index] + return IrGetValueImpl( + expression.startOffset, expression.endOffset, + parameter.type, + parameter.symbol) } return expression } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumWhenLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumWhenLowering.kt index c75039cb012..0ab73435f7b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumWhenLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumWhenLowering.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.push @@ -16,11 +17,11 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl -import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.util.getArguments @@ -87,24 +88,33 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo return expression } - private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable { - val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!! - val getOrdinal = IrCallImpl( + // Create temporary variable for subject's ordinal. + private fun createEnumOrdinalVariable(enumVariable: IrVariable) = WrappedVariableDescriptor().let { + IrVariableImpl( enumVariable.startOffset, enumVariable.endOffset, - ordinalPropertyGetter.owner.returnType, - ordinalPropertyGetter + IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, + IrVariableSymbolImpl(it), + Name.identifier(enumVariable.name.asString() + "_ordinal"), + context.irBuiltIns.intType, + isVar = false, + isConst = false, + isLateinit = false ).apply { - dispatchReceiver = IrGetValueImpl( + it.bind(this) + parent = enumVariable.parent + + val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!! + initializer = IrCallImpl( enumVariable.startOffset, enumVariable.endOffset, - enumVariable.type, enumVariable.symbol - ) + ordinalPropertyGetter.owner.returnType, + ordinalPropertyGetter + ).apply { + dispatchReceiver = IrGetValueImpl( + enumVariable.startOffset, enumVariable.endOffset, + enumVariable.type, enumVariable.symbol + ) + } } - // Create temporary variable for subject's ordinal. - val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration, - Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType) - return IrVariableImpl(enumVariable.startOffset, enumVariable.endOffset, - IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, ordinalDescriptor, - context.irBuiltIns.intType, getOrdinal) } override fun visitCall(expression: IrCall): IrExpression { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FinallyBlocksLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FinallyBlocksLowering.kt index 9c07419dc4d..c9110a0ecd5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FinallyBlocksLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FinallyBlocksLowering.kt @@ -7,16 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl -import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol @@ -25,17 +22,15 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl +import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.setDeclarationsParent import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.isNothing -import org.jetbrains.kotlin.types.typeUtil.isUnit internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, IrElementTransformerVoidWithContext() { - - private val symbols get() = context.ir.symbols + private val symbols = context.ir.symbols private interface HighLevelJump { fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression @@ -66,7 +61,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir private abstract class Scope - private class ReturnableScope(val descriptor: CallableDescriptor): Scope() + private class ReturnableScope(val symbol: IrReturnTargetSymbol): Scope() private class LoopScope(val loop: IrLoop): Scope() @@ -92,7 +87,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir } override fun visitFunctionNew(declaration: IrFunction): IrStatement { - using(ReturnableScope(declaration.descriptor)) { + using(ReturnableScope(declaration.symbol)) { return super.visitFunctionNew(declaration) } } @@ -101,7 +96,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir if (expression !is IrReturnableBlockImpl) return super.visitContainerExpression(expression) - using(ReturnableScope(expression.descriptor)) { + using(ReturnableScope(expression.symbol)) { return super.visitContainerExpression(expression) } } @@ -142,7 +137,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir expression.transformChildrenVoid(this) return performHighLevelJump( - targetScopePredicate = { it is ReturnableScope && it.descriptor == expression.returnTarget }, + targetScopePredicate = { it is ReturnableScope && it.symbol == expression.returnTargetSymbol }, jump = Return(expression.returnTargetSymbol), startOffset = expression.startOffset, endOffset = expression.endOffset, @@ -184,7 +179,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir val currentTryScope = tryScopes[index] currentTryScope.jumps.getOrPut(jump) { val type = (jump as? Return)?.target?.owner?.returnType ?: value.type - val symbol = getIrReturnableBlockSymbol(jump.toString(), type) + val symbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor()) with(currentTryScope) { irBuilder.run { val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression) @@ -223,14 +218,21 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir type = context.irBuiltIns.nothingType ) val transformedFinallyExpression = finallyExpression.transform(transformer, null) - val parameter = IrTemporaryVariableDescriptorImpl( - containingDeclaration = currentScope!!.scope.scopeOwner, - name = Name.identifier("t"), - outType = context.builtIns.throwable.defaultType - ) - val catchParameter = IrVariableImpl( - startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter, - symbols.throwable.owner.defaultType) + val catchParameter = WrappedVariableDescriptor().let { + IrVariableImpl( + startOffset, endOffset, + IrDeclarationOrigin.CATCH_PARAMETER, + IrVariableSymbolImpl(it), + Name.identifier("t"), + symbols.throwable.owner.defaultType, + isVar = false, + isConst = false, + isLateinit = false + ).apply { + it.bind(this) + parent = this@run.parent + } + } val syntheticTry = IrTryImpl( startOffset = startOffset, @@ -240,7 +242,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir catches = listOf( irCatch(catchParameter).apply { result = irBlock { - +finallyExpression.copy() + +copy(finallyExpression) +irThrow(irGet(catchParameter)) } }), @@ -248,7 +250,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir ) using(TryScope(syntheticTry, transformedFinallyExpression, this)) { val fallThroughType = aTry.type - val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", fallThroughType) + val fallThroughSymbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor()) val transformedResult = aTry.tryResult.transform(transformer, null) transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult) for (aCatch in aTry.catches) { @@ -264,39 +266,32 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol, type: IrType, value: IrExpression, finallyExpression: IrExpression): IrExpression { - val returnType = symbol.descriptor.returnType!! - return when { - returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, type) { + val returnTypeClassifier = (type as? IrSimpleType)?.classifier + return when (returnTypeClassifier) { + symbols.unit, symbols.nothing -> irBlock(value, null, type) { +irReturnableBlock(symbol, type) { +value } - +finallyExpression.copy() + +copy(finallyExpression) } else -> irBlock(value, null, type) { val tmp = irTemporary(irReturnableBlock(symbol, type) { +irReturn(symbol, value) }) - +finallyExpression.copy() + +copy(finallyExpression) +irGet(tmp) } } } - private fun getFakeFunctionDescriptor(name: String, returnType: KotlinType) = - SimpleFunctionDescriptorImpl.create(currentScope!!.scope.scopeOwner, Annotations.EMPTY, name.synthesizedName, - CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE).apply { - initialize(null, null, emptyList(), emptyList(), returnType, Modality.ABSTRACT, Visibilities.PRIVATE) - } - - private fun getIrReturnableBlockSymbol(name: String, returnType: IrType): IrReturnableBlockSymbol = - IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType.toKotlinType())) - - private inline fun T.copy() = this.deepCopyWithVariables() + private inline fun IrBuilderWithScope.copy(element: T) = + element.deepCopyWithVariables().setDeclarationsParent(parent) fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) = IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value) - inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, type: IrType, body: IrBlockBuilder.() -> Unit) = + private inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, + type: IrType, body: IrBlockBuilder.() -> Unit) = IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null, IrBlockBuilder(context, scope, startOffset, endOffset, null, type) .block(body).statements) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index ecec92791f1..7bd4fd4fa86 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -10,6 +10,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole +import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke @@ -150,7 +151,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC if (!callSite.descriptor.needsInlining) return callSite val functionDescriptor = callSite.descriptor.resolveFakeOverride().original - if (functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor) + if (callSite.symbol == context.ir.symbols.isInitializedGetter) return callSite val callee = getFunctionDeclaration(functionDescriptor) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt index 0fcd2b2dcfe..3a36a71a501 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt @@ -7,13 +7,12 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.isNonGeneratedAnnotation import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall import org.jetbrains.kotlin.ir.declarations.* @@ -21,10 +20,10 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor internal class InitializersLowering(val context: CommonBackendContext) : ClassLoweringPass { @@ -41,8 +40,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo fun lowerInitializers() { collectAndRemoveInitializers() - val initializerMethodSymbol = createInitializerMethod() - lowerConstructors(initializerMethodSymbol) + val initializeMethodSymbol = createInitializerMethod() + lowerConstructors(initializeMethodSymbol) } private fun collectAndRemoveInitializers() { @@ -63,7 +62,9 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo val initializer = declaration.initializer ?: return declaration val startOffset = initializer.startOffset val endOffset = initializer.endOffset - initializers.add(IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, + initializers.add(IrBlockImpl(startOffset, endOffset, + context.irBuiltIns.unitType, + STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, listOf( IrSetFieldImpl(startOffset, endOffset, declaration.symbol, IrGetValueImpl( @@ -72,7 +73,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo ), initializer.expression, context.irBuiltIns.unitType, - STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))) + STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))) + ) declaration.initializer = null return declaration } @@ -88,52 +90,54 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo private fun createInitializerMethod(): IrSimpleFunctionSymbol? { if (irClass.declarations.any { it is IrConstructor && it.isPrimary }) return null // Place initializers in the primary constructor. - val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ irClass.descriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ "INITIALIZER".synthesizedName, - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE) - initializerMethodDescriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ irClass.descriptor.thisAsReceiverParameter, - /* typeParameters = */ listOf(), - /* unsubstitutedValueParameters = */ listOf(), - /* returnType = */ context.builtIns.unitType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PRIVATE) + val startOffset = irClass.startOffset val endOffset = irClass.endOffset - val initializer = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER, - initializerMethodDescriptor, context.irBuiltIns.unitType) + val initializeFun = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER, + IrSimpleFunctionSymbolImpl(it), + "INITIALIZER".synthesizedName, + Visibilities.PRIVATE, + Modality.FINAL, + context.irBuiltIns.unitType, + isInline = false, + isSuspend = false, + isExternal = false, + isTailrec = false + ).apply { + it.bind(this) + parent = irClass + irClass.declarations.add(this) - initializer.body = IrBlockBodyImpl(startOffset, endOffset, initializers) + createDispatchReceiverParameter() - initializer.parent = irClass - initializer.createDispatchReceiverParameter() + body = IrBlockBodyImpl(startOffset, endOffset, initializers) + } + } - initializers.forEach { - it.transformChildrenVoid(object : IrElementTransformerVoid() { + for (initializer in initializers) { + initializer.transformChildrenVoid(object : IrElementTransformerVoid() { override fun visitGetValue(expression: IrGetValue): IrExpression { if (expression.symbol == irClass.thisReceiver!!.symbol) { return IrGetValueImpl( expression.startOffset, expression.endOffset, - initializer.dispatchReceiverParameter!!.type, - initializer.dispatchReceiverParameter!!.symbol + initializeFun.dispatchReceiverParameter!!.type, + initializeFun.dispatchReceiverParameter!!.symbol ) } return expression } }) + initializer.patchDeclarationParents(initializeFun) } - irClass.declarations.add(initializer) - - return initializer.symbol + return initializeFun.symbol } - private fun lowerConstructors(initializerMethodSymbol: IrSimpleFunctionSymbol?) { + private fun lowerConstructors(initializeMethodSymbol: IrSimpleFunctionSymbol?) { if (irClass.kind == ClassKind.ANNOTATION_CLASS) { if (irClass.isNonGeneratedAnnotation()) return @@ -158,14 +162,16 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo blockBody.statements.transformFlat { when { it is IrInstanceInitializerCall -> { - if (initializerMethodSymbol == null) { - assert(declaration.descriptor.isPrimary) + if (initializeMethodSymbol == null) { + assert(declaration.isPrimary) + for (initializer in initializers) + initializer.patchDeclarationParents(declaration) initializers } else { val startOffset = it.startOffset val endOffset = it.endOffset listOf(IrCallImpl(startOffset, endOffset, - context.irBuiltIns.unitType, initializerMethodSymbol + context.irBuiltIns.unitType, initializeMethodSymbol ).apply { dispatchReceiver = IrGetValueImpl( startOffset, endOffset, @@ -174,20 +180,24 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo }) } } - /** - * IR for kotlin.Any is: - * BLOCK_BODY - * DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' - * INSTANCE_INITIALIZER_CALL classDescriptor='Any' - * - * to avoid possible recursion we manually reject body generation for Any. - */ - it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any - && it.descriptor == declaration.descriptor -> listOf() + + /** + * IR for kotlin.Any is: + * BLOCK_BODY + * DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + * INSTANCE_INITIALIZER_CALL classDescriptor='Any' + * + * to avoid possible recursion we manually reject body generation for Any. + */ + it is IrDelegatingConstructorCall + && irClass.symbol == context.irBuiltIns.anyClass + && it.symbol == declaration.symbol -> { + listOf() + } + else -> null } } - declaration.parent = irClass return declaration } 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 790f0a145f5..e4e92f69875 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 @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext 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.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrFunction @@ -21,9 +20,12 @@ 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.types.IrSimpleType +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.visitors.transformChildrenVoid -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver internal class InnerClassLowering(val context: Context) : ClassLoweringPass { override fun lower(irClass: IrClass) { @@ -31,12 +33,10 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { } private inner class InnerClassTransformer(val irClass: IrClass) { - val classDescriptor = irClass.descriptor - lateinit var outerThisFieldSymbol: IrFieldSymbol fun lowerInnerClass() { - if (!irClass.descriptor.isInner) return + if (!irClass.isInner) return createOuterThisField() lowerOuterThisReferences() @@ -84,10 +84,9 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { override fun visitGetValue(expression: IrGetValue): IrExpression { expression.transformChildrenVoid(this) - val implicitThisClass = expression.descriptor.getClassDescriptorForImplicitThis() ?: - return expression + val implicitThisClass = (expression.symbol.owner.parent as? IrClass) ?: return expression - if (implicitThisClass == classDescriptor) return expression + if (implicitThisClass == irClass) return expression val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol @@ -97,27 +96,27 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { var irThis: IrExpression var innerClass: IrClass - if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) { + 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?.descriptor == irClass.thisReceiver!!.descriptor) { - currentFunctionReceiver - } else { - irClass.thisReceiver!! - } + 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 $classDescriptor") + 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.descriptor != implicitThisClass) { + while (innerClass != implicitThisClass) { if (!innerClass.isInner) { // Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is - // should be transformed by closures conversion. @@ -134,23 +133,13 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { val outer = innerClass.parent innerClass = outer as? IrClass ?: - throw AssertionError("Unexpected containing declaration for inner class ${innerClass.descriptor}: $outer") + throw AssertionError("Unexpected containing declaration for inner class ${innerClass.dump()}: $outer") } return irThis } }) } - - private fun ValueDescriptor.getClassDescriptorForImplicitThis(): ClassDescriptor? { - if (this is ReceiverParameterDescriptor) { - val receiverValue = value - if (receiverValue is ImplicitClassReceiver) { - return receiverValue.classDescriptor - } - } - return null - } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt index a299517bfa0..5670ae31cb5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/LateinitLowering.kt @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.VariableDescriptor -import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -21,45 +18,29 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrPropertyReference import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.acceptVoid +import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol +import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name internal class LateinitLowering( val context: Context, private val generateParameterNameInAssertion: Boolean = false ) : FileLoweringPass { - private val isInitializedGetterDescriptor = context.ir.symbols.isInitializedGetterDescriptor + private val isInitializedGetter = context.ir.symbols.isInitializedGetter override fun lower(irFile: IrFile) { - val lateinitPropertyToField = mutableMapOf() - irFile.acceptVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitProperty(declaration: IrProperty) { - super.visitProperty(declaration) - - if (declaration.isLateinit && declaration.descriptor.kind.isReal) { - lateinitPropertyToField[declaration.descriptor] = declaration.backingField!! - } - } - }) - irFile.transformChildrenVoid(object : IrBuildingTransformer(context) { override fun visitVariable(declaration: IrVariable): IrStatement { declaration.transformChildrenVoid(this) - val descriptor = declaration.descriptor - if (!descriptor.isLateInit) return declaration + if (!declaration.isLateinit) return declaration - assert(declaration.initializer == null, { "'lateinit' modifier is not allowed for variables with initializer" }) - assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" }) + assert(declaration.initializer == null) { + "'lateinit' modifier is not allowed for variables with initializer" + } builder.at(declaration).run { declaration.initializer = irNull() } @@ -68,16 +49,14 @@ internal class LateinitLowering( override fun visitGetValue(expression: IrGetValue): IrExpression { val symbol = expression.symbol - val descriptor = symbol.descriptor as? VariableDescriptor - if (descriptor == null || !descriptor.isLateInit) return expression + if (symbol !is IrVariableSymbol || !symbol.owner.isLateinit) return expression - assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" }) builder.at(expression).run { return irBlock(expression) { // TODO: do data flow analysis to check if value is proved to be not-null. +irIfThen( irEqualsNull(irGet(expression.type, symbol)), - throwUninitializedPropertyAccessException(symbol) + throwUninitializedPropertyAccessException(symbol.owner.name) ) +irGet(expression.type, symbol) } @@ -87,17 +66,17 @@ internal class LateinitLowering( override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) - val descriptor = expression.descriptor - if (descriptor != isInitializedGetterDescriptor) return expression + if (expression.symbol != isInitializedGetter) return expression val propertyReference = expression.extensionReceiver!! as IrPropertyReference - assert(propertyReference.extensionReceiver == null, { "'lateinit' modifier is not allowed on extension properties" }) - val propertyDescriptor = propertyReference.descriptor.resolveFakeOverride().original + assert(propertyReference.extensionReceiver == null) { + "'lateinit' modifier is not allowed on extension properties" + } + val getter = propertyReference.getter?.owner ?: TODO(propertyReference.dump()) + val property = getter.resolveFakeOverride().correspondingProperty!! - val type = propertyDescriptor.type - assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" }) builder.at(expression).run { - val field = lateinitPropertyToField[propertyDescriptor]!! + val field = property.backingField!! val fieldValue = irGetField(propertyReference.dispatchReceiver, field) return irNotEquals(fieldValue, irNull()) } @@ -106,13 +85,15 @@ internal class LateinitLowering( override fun visitProperty(declaration: IrProperty): IrStatement { declaration.transformChildrenVoid(this) - if (!declaration.descriptor.isLateInit || !declaration.descriptor.kind.isReal) + if (!declaration.isLateinit || !declaration.isReal) return declaration val backingField = declaration.backingField!! transformGetter(backingField, declaration.getter!!) - assert(backingField.initializer == null, { "'lateinit' modifier is not allowed for properties with initializer" }) + assert(backingField.initializer == null) { + "'lateinit' modifier is not allowed for properties with initializer" + } val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset) irBuilder.run { backingField.initializer = irExprBody(irNull()) @@ -122,8 +103,6 @@ internal class LateinitLowering( } private fun transformGetter(backingField: IrField, getter: IrFunction) { - val type = backingField.descriptor.type - assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" }) val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset) irBuilder.run { getter.body = irBlockBody { @@ -134,7 +113,7 @@ internal class LateinitLowering( context.irBuiltIns.nothingType, irNotEquals(irGet(resultVar), irNull()), irReturn(irGet(resultVar)), - throwUninitializedPropertyAccessException(backingField.symbol) + throwUninitializedPropertyAccessException(backingField.name) ) } } @@ -142,7 +121,7 @@ internal class LateinitLowering( }) } - private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) = + private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: Name) = irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply { if (generateParameterNameInAssertion) { putValueArgument( @@ -151,7 +130,7 @@ internal class LateinitLowering( startOffset, endOffset, context.irBuiltIns.stringType, - backingFieldSymbol.descriptor.name.asString() + name.asString() ) ) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReturnsInsertionLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReturnsInsertionLowering.kt index 37a73a78492..3d1555ea638 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReturnsInsertionLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReturnsInsertionLowering.kt @@ -8,19 +8,20 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.irGetObject import org.jetbrains.kotlin.ir.builders.irReturn +import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrBlockBody +import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.types.typeUtil.isUnit internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass { + private val symbols = context.ir.symbols override fun lower(irFile: IrFile) { irFile.acceptVoid(object : IrElementVisitorVoid { @@ -32,10 +33,10 @@ internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass declaration.acceptChildrenVoid(this) val body = declaration.body - if ((declaration.descriptor is ConstructorDescriptor || declaration.descriptor.returnType!!.isUnit()) && body != null) { + if ((declaration is IrConstructor || declaration.returnType.classifierOrNull == symbols.unit) && body != null) { val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset) irBuilder.run { - (body as IrBlockBody).statements += irReturn(irGetObject(this@ReturnsInsertionLowering.context.ir.symbols.unit)) + (body as IrBlockBody).statements += irReturn(irGetObject(symbols.unit)) } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt deleted file mode 100644 index 25019f9fafe..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan.lower - -import org.jetbrains.kotlin.backend.common.* -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrVariable -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.symbols.IrValueSymbol -import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol -import org.jetbrains.kotlin.ir.visitors.* -import java.util.* - -object CoroutineIntrinsicLambdaOrigin: IrStatementOriginImpl("Coroutine intrinsic lambda") - -// TODO: Fix .parent for variables and use from common backend. -class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass { - override fun lower(irFunction: IrFunction) { - SharedVariablesTransformer(irFunction).lowerSharedVariables() - } - - private inner class SharedVariablesTransformer(val irFunction: IrFunction) { - val sharedVariables = mutableSetOf() - - fun lowerSharedVariables() { - collectSharedVariables() - if (sharedVariables.isEmpty()) return - - rewriteSharedVariables() - } - - private fun collectSharedVariables() { - irFunction.acceptVoid(object : IrElementVisitorVoid { - val relevantVars = mutableSetOf() - val functionsVariables = mutableListOf>() - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitFunction(declaration: IrFunction) { - functionsVariables.push(mutableSetOf()) - declaration.acceptChildrenVoid(this) - functionsVariables.pop() - } - - override fun visitContainerExpression(expression: IrContainerExpression) { - if (expression !is IrReturnableBlock || expression.origin != CoroutineIntrinsicLambdaOrigin) - super.visitContainerExpression(expression) - else { - functionsVariables.push(mutableSetOf()) - expression.acceptChildrenVoid(this) - functionsVariables.pop() - } - } - - override fun visitVariable(declaration: IrVariable) { - declaration.acceptChildrenVoid(this) - - if (declaration.isVar) { - relevantVars.add(declaration) - functionsVariables.peek()!!.add(declaration) - } - } - - override fun visitVariableAccess(expression: IrValueAccessExpression) { - expression.acceptChildrenVoid(this) - - val value = expression.symbol.owner - //if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) { - // TODO: fix lowerings to match check `(value as IrVariable).parent != currentDeclaration` - if (value in relevantVars && !functionsVariables.peek()!!.contains(value)) { - sharedVariables.add(value as IrVariable) - } - } - }) - } - - private fun rewriteSharedVariables() { - val transformedVariableSymbols = HashMap() - - irFunction.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitVariable(declaration: IrVariable): IrStatement { - declaration.transformChildrenVoid(this) - - if (declaration !in sharedVariables) return declaration - - val newDeclaration = context.sharedVariablesManager.declareSharedVariable(declaration) - transformedVariableSymbols[declaration.symbol] = newDeclaration.symbol - - return context.sharedVariablesManager.defineSharedValue(declaration, newDeclaration) - } - }) - - irFunction.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - expression.transformChildrenVoid(this) - - val newSymbol = getTransformedSymbol(expression.symbol) ?: return expression - - return context.sharedVariablesManager.getSharedValue(newSymbol, expression) - } - - override fun visitSetVariable(expression: IrSetVariable): IrExpression { - expression.transformChildrenVoid(this) - - val newDescriptor = getTransformedSymbol(expression.symbol) ?: return expression - - return context.sharedVariablesManager.setSharedValue(newDescriptor, expression) - } - - private fun getTransformedSymbol(oldSymbol: IrValueSymbol): IrVariableSymbol? = - transformedVariableSymbols.getOrElse(oldSymbol) { - assert(oldSymbol.owner !in sharedVariables) { - "Shared variable is not transformed: $oldSymbol" - } - null - } - }) - } - } -} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt index 8100615971b..a0cbd25ea62 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt @@ -6,27 +6,28 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* -import org.jetbrains.kotlin.backend.common.descriptors.getFunction +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith import org.jetbrains.kotlin.config.languageVersionSettings 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.ClassDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* -import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl @@ -34,15 +35,16 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.storage.LockBasedStorageManager internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass { private object STATEMENT_ORIGIN_COROUTINE_IMPL : IrStatementOriginImpl("COROUTINE_IMPL") private object DECLARATION_ORIGIN_COROUTINE_IMPL : IrDeclarationOriginImpl("COROUTINE_IMPL") - private val builtCoroutines = mutableMapOf() - private val suspendLambdas = mutableMapOf() + private val builtCoroutines = mutableMapOf() + private val suspendLambdas = mutableMapOf() + + private val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend override fun lower(irFile: IrFile) { markSuspendLambdas(irFile) @@ -52,7 +54,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private fun buildCoroutines(irFile: IrFile) { irFile.declarations.transformFlat(::tryTransformSuspendFunction) - irFile.acceptVoid(object: IrElementVisitorVoid { + irFile.acceptVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } @@ -65,8 +67,8 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass } private fun tryTransformSuspendFunction(element: IrElement) = - if (element is IrFunction && element.descriptor.isSuspend && element.descriptor.modality != Modality.ABSTRACT) - transformSuspendFunction(element, suspendLambdas[element.descriptor]) + if (element is IrSimpleFunction && element.isSuspend && element.modality != Modality.ABSTRACT) + transformSuspendFunction(element, suspendLambdas[element]) else null private fun markSuspendLambdas(irElement: IrElement) { @@ -78,9 +80,9 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass override fun visitFunctionReference(expression: IrFunctionReference) { expression.acceptChildrenVoid(this) - val descriptor = expression.descriptor - if (descriptor.isSuspend) - suspendLambdas.put(descriptor, expression) + val function = expression.symbol.owner + if (function.isSuspend) + suspendLambdas[function] = expression } }) } @@ -91,15 +93,15 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { expression.transformChildrenVoid(this) - val descriptor = expression.descriptor - if (!descriptor.isSuspend) + val function = expression.symbol.owner + if (!function.isSuspend) return expression - val coroutine = builtCoroutines[descriptor] - ?: throw Error("The coroutine for $descriptor has not been built") + val coroutine = builtCoroutines[function] + ?: throw Error("The coroutine for $function has not been built") val constructorParameters = coroutine.coroutineConstructor.valueParameters val expressionArguments = expression.getArguments().map { it.second } - assert(constructorParameters.size == expressionArguments.size, - { "Inconsistency between callable reference to suspend lambda and the corresponding coroutine" }) + assert(constructorParameters.size == expressionArguments.size) + { "Inconsistency between callable reference to suspend lambda and the corresponding coroutine" } val irBuilder = context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset) irBuilder.run { return irCall(coroutine.coroutineConstructor.symbol).apply { @@ -133,7 +135,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass is SuspendFunctionKind.NEEDS_STATE_MACHINE -> { val coroutine = buildCoroutine(irFunction, functionReference) // Coroutine implementation. - if (suspendLambdas.contains(irFunction.descriptor)) // Suspend lambdas are called through factory method , + if (suspendLambdas.contains(irFunction)) // Suspend lambdas are called through factory method , listOf(coroutine) // thus we can eliminate original body. else listOf( @@ -145,14 +147,14 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass } private fun getSuspendFunctionKind(irFunction: IrFunction): SuspendFunctionKind { - if (suspendLambdas.contains(irFunction.descriptor)) + if (suspendLambdas.contains(irFunction)) return SuspendFunctionKind.NEEDS_STATE_MACHINE // Suspend lambdas always need coroutine implementation. val body = irFunction.body ?: return SuspendFunctionKind.NO_SUSPEND_CALLS var numberOfSuspendCalls = 0 - body.acceptVoid(object: IrElementVisitorVoid { + body.acceptVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } @@ -160,7 +162,8 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass override fun visitCall(expression: IrCall) { expression.acceptChildrenVoid(this) - if (expression.descriptor.isSuspend) + val callee = expression.symbol.owner + if (callee.isSuspend) ++numberOfSuspendCalls } }) @@ -181,10 +184,10 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass * } * } */ - loop@while (true) { - when { - value is IrBlock && value.statements.size == 1 -> value = value.statements.first() - value is IrReturn -> value = value.value + loop@ while (true) { + value = when { + value is IrBlock && value.statements.size == 1 -> value.statements.first() + value is IrReturn -> value.value else -> break@loop } } @@ -192,37 +195,36 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass } else -> null } - val suspendCallAtEnd = lastCall != null && lastCall.descriptor.isSuspend // Suspend call. + val suspendCallAtEnd = lastCall != null && lastCall.symbol.owner.isSuspend // Suspend call. return when { - numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS + numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS numberOfSuspendCalls == 1 && suspendCallAtEnd -> SuspendFunctionKind.DELEGATING(lastCall!!) - else -> SuspendFunctionKind.NEEDS_STATE_MACHINE + else -> SuspendFunctionKind.NEEDS_STATE_MACHINE } } private val symbols = context.ir.symbols private val getContinuation = symbols.getContinuation.owner private val continuationClassSymbol = getContinuation.returnType.classifierOrFail as IrClassSymbol - private val returnIfSuspendedDescriptor = context.getInternalFunctions("returnIfSuspended").single() + private val returnIfSuspended = symbols.returnIfSuspended private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) { val returnValue = - if (delegatingCall.descriptor.original == returnIfSuspendedDescriptor) + if (delegatingCall.symbol == returnIfSuspended) delegatingCall.getValueArgument(0)!! else delegatingCall context.createIrBuilder(irFunction.symbol).run { val statements = (irFunction.body as IrBlockBody).statements val lastStatement = statements.last() - assert (lastStatement == delegatingCall || lastStatement is IrReturn) { "Unexpected statement $lastStatement" } + assert(lastStatement == delegatingCall || lastStatement is IrReturn) { "Unexpected statement $lastStatement" } statements[statements.size - 1] = irReturn(returnValue) } } private fun buildCoroutine(irFunction: IrFunction, functionReference: IrFunctionReference?): IrClass { - val descriptor = irFunction.descriptor val coroutine = CoroutineBuilder(irFunction, functionReference).build() - builtCoroutines.put(descriptor, coroutine) + builtCoroutines[irFunction] = coroutine if (functionReference == null) { // It is not a lambda - replace original function with a call to constructor of the built coroutine. @@ -252,19 +254,50 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) { + private val startOffset = irFunction.startOffset + private val endOffset = irFunction.endOffset private val functionParameters = irFunction.explicitParameters private val boundFunctionParameters = functionReference?.getArgumentsWithIr()?.map { it.first } private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it } + private val coroutineClass = WrappedClassDescriptor().let { + IrClassImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrClassSymbolImpl(it), + "${irFunction.name}\$COROUTINE\$${context.coroutineCount++}".synthesizedName, + ClassKind.CLASS, + Visibilities.PRIVATE, + Modality.FINAL, + isCompanion = false, + isInline = false, + isInner = false, + isData = false, + isExternal = false + ).apply { + it.bind(this) + parent = irFunction.parent + createParameterDeclarations() + irFunction.typeParameters.mapTo(typeParameters) { typeParam -> + typeParam.copyToWithoutSuperTypes(this).apply { superTypes += typeParam.superTypes } + } + } + } + private val coroutineClassThis = coroutineClass.thisReceiver!! + + private val continuationType = continuationClassSymbol.typeWith(irFunction.returnType) + + // Save all arguments to fields. + private val argumentToPropertiesMap = functionParameters.associate { + it to addField(it.name, it.type, false) + } + + private val labelField = addField(Name.identifier("label"), symbols.nativePtrType, true) + private var tempIndex = 0 private var suspensionPointIdIndex = 0 - private lateinit var labelField: IrField private lateinit var suspendResult: IrVariable private lateinit var resultArgument: IrValueParameter - private lateinit var coroutineClassDescriptor: ClassDescriptorImpl - private lateinit var coroutineClass: IrClassImpl - private lateinit var coroutineClassThis: IrValueParameter - private lateinit var argumentToPropertiesMap: Map private val baseClass = (if (irFunction.isRestrictedSuspendFunction(context.config.configuration.languageVersionSettings)) { @@ -279,600 +312,413 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass private val create1CompletionParameter = create1Function.valueParameters[0] fun build(): BuiltCoroutine { - val superTypes = mutableListOf(baseClass.defaultType) + val superTypes = mutableListOf(baseClass.defaultType) var suspendFunctionClass: IrClass? = null var functionClass: IrClass? = null - var suspendFunctionClassTypeArguments: List? = null - var functionClassTypeArguments: List? = null + val suspendFunctionClassTypeArguments: List? + val functionClassTypeArguments: List? if (unboundFunctionParameters != null) { // Suspend lambda inherits SuspendFunction. val numberOfParameters = unboundFunctionParameters.size - suspendFunctionClass = context.ir.symbols.suspendFunctions[numberOfParameters].owner + suspendFunctionClass = symbols.suspendFunctions[numberOfParameters].owner val unboundParameterTypes = unboundFunctionParameters.map { it.type } suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.returnType superTypes += suspendFunctionClass.typeWith(suspendFunctionClassTypeArguments) - functionClass = context.ir.symbols.functions[numberOfParameters + 1].owner - val continuationType = continuationClassSymbol.typeWith(irFunction.returnType) + functionClass = symbols.functions[numberOfParameters + 1].owner functionClassTypeArguments = unboundParameterTypes + continuationType + context.irBuiltIns.anyNType superTypes += functionClass.typeWith(functionClassTypeArguments) - } - coroutineClassDescriptor = ClassDescriptorImpl( - /* containingDeclaration = */ irFunction.descriptor.containingDeclaration, - /* name = */ "${irFunction.descriptor.name}\$COROUTINE\$${context.coroutineCount++}".synthesizedName, - /* modality = */ Modality.FINAL, - /* kind = */ ClassKind.CLASS, - /* superTypes = */ superTypes.map { it.toKotlinType() }, - /* source = */ SourceElement.NO_SOURCE, - /* isExternal = */ false, - /* storageManager = */ LockBasedStorageManager.NO_LOCKS - ).also { - it.initialize(stub("coroutine class"), stub("coroutine class constructors"), null) - } - coroutineClass = IrClassImpl( - startOffset = irFunction.startOffset, - endOffset = irFunction.endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - descriptor = coroutineClassDescriptor - ) - coroutineClass.parent = irFunction.parent - coroutineClass.createParameterDeclarations() - coroutineClassThis = coroutineClass.thisReceiver!! - labelField = createField( - irFunction.startOffset, - irFunction.endOffset, - symbols.nativePtrType, - Name.identifier("label"), - true, - IrDeclarationOrigin.DEFINED, - coroutineClass.descriptor - ) - coroutineClass.addChild(labelField) + val coroutineConstructor = buildConstructor() + val superInvokeSuspendFunction = baseClass.simpleFunctions().single { it.name.asString() == "invokeSuspend" } + val invokeSuspendMethod = buildInvokeSuspendMethod(superInvokeSuspendFunction, coroutineClass) - val overriddenMap = mutableMapOf() - val coroutineConstructorBuilder = createConstructorBuilder() - coroutineConstructorBuilder.initialize() - - val invokeSuspendFunction = baseClass.simpleFunctions() - .single { it.name.asString() == "invokeSuspend" } - val invokeSuspendMethodBuilder = createInvokeSuspendMethodBuilder(invokeSuspendFunction, coroutineClass) - invokeSuspendMethodBuilder.initialize() - overriddenMap += invokeSuspendFunction.descriptor to invokeSuspendMethodBuilder.symbol.descriptor - - var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder? = null - var createMethodBuilder: SymbolWithIrBuilder? = null - var invokeMethodBuilder: SymbolWithIrBuilder? = null + var coroutineFactoryConstructor: IrConstructor? = null + val createMethod: IrSimpleFunction? if (functionReference != null) { // Suspend lambda - create factory methods. - coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!) + coroutineFactoryConstructor = buildFactoryConstructor(boundFunctionParameters!!) - val createFunctionDescriptor = baseClass.descriptor.unsubstitutedMemberScope - .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) - .atMostOne { it.valueParameters.size == unboundFunctionParameters!!.size + 1 } - createMethodBuilder = createCreateMethodBuilder( - unboundArgs = unboundFunctionParameters!!, - superFunctionDescriptor = createFunctionDescriptor, - coroutineConstructor = coroutineConstructorBuilder.ir, - coroutineClass = coroutineClass) - createMethodBuilder.initialize() - if (createFunctionDescriptor != null) - overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor + val createFunctionSymbol = + baseClass.simpleFunctions() + .atMostOne { + it.name.asString() == "create" + && it.valueParameters.size == unboundFunctionParameters!!.size + 1 + } + ?.symbol + createMethod = buildCreateMethod( + unboundArgs = unboundFunctionParameters!!, + superFunctionSymbol = createFunctionSymbol, + coroutineConstructor = coroutineConstructor) + val invokeFunctionSymbol = + functionClass!!.simpleFunctions().single { it.name.asString() == "invoke" }.symbol + val suspendInvokeFunctionSymbol = + suspendFunctionClass!!.simpleFunctions().single { it.name.asString() == "invoke" }.symbol - val invokeFunctionDescriptor = functionClass!!.descriptor - .getFunction("invoke", functionClassTypeArguments!!.map { it.toKotlinType() }) - val suspendInvokeFunctionDescriptor = suspendFunctionClass!!.descriptor - .getFunction("invoke", suspendFunctionClassTypeArguments!!.map { it.toKotlinType() }) - invokeMethodBuilder = createInvokeMethodBuilder( - suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, - functionInvokeFunctionDescriptor = invokeFunctionDescriptor, - createFunction = createMethodBuilder.ir, - invokeSuspendFunction = invokeSuspendMethodBuilder.ir, - coroutineClass = coroutineClass) + buildInvokeMethod( + suspendFunctionInvokeFunctionSymbol = suspendInvokeFunctionSymbol, + functionInvokeFunctionSymbol = invokeFunctionSymbol, + createFunction = createMethod, + invokeSuspendFunction = invokeSuspendMethod) } - coroutineClass.addChild(coroutineConstructorBuilder.ir) - - coroutineFactoryConstructorBuilder?.let { - it.initialize() - coroutineClass.addChild(it.ir) - } - - createMethodBuilder?.let { - coroutineClass.addChild(it.ir) - } - - invokeMethodBuilder?.let { - it.initialize() - coroutineClass.addChild(it.ir) - } - - coroutineClass.addChild(invokeSuspendMethodBuilder.ir) - - coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes) + coroutineClass.superTypes += superTypes + coroutineClass.addFakeOverrides() return BuiltCoroutine( - coroutineClass = coroutineClass, - coroutineConstructor = coroutineFactoryConstructorBuilder?.ir - ?: coroutineConstructorBuilder.ir, - invokeSuspendFunction = invokeSuspendMethodBuilder.ir) + coroutineClass = coroutineClass, + coroutineConstructor = coroutineFactoryConstructor ?: coroutineConstructor, + invokeSuspendFunction = invokeSuspendMethod) } - private fun createConstructorBuilder() - = object : SymbolWithIrBuilder() { + private fun buildConstructor() = WrappedClassConstructorDescriptor().let { + IrConstructorImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrConstructorSymbolImpl(it), + baseClassConstructor.name, + Visibilities.PUBLIC, + coroutineClass.defaultType, + isInline = false, + isExternal = false, + isPrimary = false + ).apply { + it.bind(this) + parent = coroutineClass + coroutineClass.declarations += this - override fun buildSymbol() = IrConstructorSymbolImpl( - ClassConstructorDescriptorImpl.create( - /* containingDeclaration = */ coroutineClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* isPrimary = */ false, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - private lateinit var constructorParameters: List - - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl - constructorParameters = ( - functionParameters - + baseClassConstructor.valueParameters[0] // completion. - ).mapIndexed { index, parameter -> - - val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index) - parameter.copy(parameterDescriptor) + functionParameters.mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index) } + val continuationParameter = baseClassConstructor.valueParameters[0] + valueParameters += continuationParameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, + index = valueParameters.size, type = continuationType) - descriptor.initialize( - constructorParameters.map { it.descriptor as ValueParameterDescriptor }, - Visibilities.PUBLIC - ) - descriptor.returnType = coroutineClassDescriptor.defaultType - } - - override fun buildIr(): IrConstructor { - // Save all arguments to fields. - argumentToPropertiesMap = functionParameters.associate { - it.descriptor to addField(it.name, it.type, false) - } - - val startOffset = irFunction.startOffset - val endOffset = irFunction.endOffset - return IrConstructorImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - symbol = symbol, - returnType = coroutineClass.defaultType - ).apply { - - this.valueParameters += constructorParameters - - val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) - body = irBuilder.irBlockBody { - val completionParameter = valueParameters.last() - +IrDelegatingConstructorCallImpl(startOffset, endOffset, - context.irBuiltIns.unitType, - baseClassConstructor.symbol, baseClassConstructor.descriptor).apply { - putValueArgument(0, irGet(completionParameter)) - } - +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType) - - +irSetField(irGet(coroutineClassThis), labelField, irCall(symbols.getNativeNullPtr.owner)) - - functionParameters.forEachIndexed { index, parameter -> - +irSetField( - irGet(coroutineClassThis), - argumentToPropertiesMap[parameter.descriptor]!!, - irGet(valueParameters[index]) - ) - } + val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) + body = irBuilder.irBlockBody { + val completionParameter = valueParameters.last() + +irDelegatingConstructorCall(baseClassConstructor).apply { + putValueArgument(0, irGet(completionParameter)) } - } - } - } + +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType) - private fun createFactoryConstructorBuilder(boundParams: List) - = object : SymbolWithIrBuilder() { + +irSetField(irGet(coroutineClassThis), labelField, irCall(symbols.getNativeNullPtr.owner)) - override fun buildSymbol() = IrConstructorSymbolImpl( - ClassConstructorDescriptorImpl.create( - /* containingDeclaration = */ coroutineClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* isPrimary = */ false, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - lateinit var constructorParameters: List - - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl - constructorParameters = boundParams.mapIndexed { index, parameter -> - val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index) - parameter.copy(parameterDescriptor) - } - descriptor.initialize( - constructorParameters.map { it.descriptor as ValueParameterDescriptor }, - Visibilities.PUBLIC - ) - descriptor.returnType = coroutineClassDescriptor.defaultType - } - - override fun buildIr(): IrConstructor { - val startOffset = irFunction.startOffset - val endOffset = irFunction.endOffset - return IrConstructorImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - symbol = symbol, - returnType = coroutineClass.defaultType - ).apply { - - this.valueParameters += constructorParameters - - val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) - body = irBuilder.irBlockBody { - +IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, - baseClassConstructor.symbol, baseClassConstructor.descriptor).apply { - putValueArgument(0, irNull()) // Completion. - } - +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, - context.irBuiltIns.unitType) - // Save all arguments to fields. - boundParams.forEachIndexed { index, parameter -> - +irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter.descriptor]!!, - irGet(valueParameters[index])) - } - } - } - } - } - - private fun createCreateMethodBuilder(unboundArgs: List, - superFunctionDescriptor: FunctionDescriptor?, - coroutineConstructor: IrConstructor, - coroutineClass: IrClass) - = object: SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ coroutineClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("create"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - lateinit var parameters: List - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - parameters = ( - unboundArgs + create1CompletionParameter - ).mapIndexed { index, parameter -> - parameter.copy(parameter.descriptor.copyAsValueParameter(descriptor, index)) - } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor }, - /* unsubstitutedReturnType = */ coroutineClassDescriptor.defaultType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PRIVATE).apply { - if (superFunctionDescriptor != null) { - overriddenDescriptors = listOf(superFunctionDescriptor) - } - } - } - - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunction.startOffset - val endOffset = irFunction.endOffset - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - symbol = symbol, - returnType = coroutineClass.defaultType - ).apply { - parent = coroutineClass - - this.valueParameters += parameters - this.createDispatchReceiverParameter() - - val thisReceiver = this.dispatchReceiverParameter!! - - val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - irCall(coroutineConstructor).apply { - var unboundIndex = 0 - val unboundArgsSet = unboundArgs.toSet() - functionParameters.map { - if (unboundArgsSet.contains(it)) - irGet(valueParameters[unboundIndex++]) - else - irGetField(irGet(thisReceiver), argumentToPropertiesMap[it.descriptor]!!) - }.forEachIndexed { index, argument -> - putValueArgument(index, argument) - } - putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex])) - assert(unboundIndex == valueParameters.size - 1, - { "Not all arguments of are used" }) - }) - } - } - } - } - - private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor, - functionInvokeFunctionDescriptor: FunctionDescriptor, - createFunction: IrFunction, - invokeSuspendFunction: IrFunction, - coroutineClass: IrClass) - = object: SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ coroutineClassDescriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ Name.identifier("invoke"), - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE - ) - ) - - lateinit var parameters: List - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - parameters = createFunction.valueParameters - // Skip completion - invoke() already has it implicitly as a suspend function. - .take(createFunction.valueParameters.size - 1) - .map { it.copy(it.descriptor.copyAsValueParameter(descriptor, it.index)) } - - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor }, - /* unsubstitutedReturnType = */ irFunction.descriptor.returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PRIVATE).apply { - overriddenDescriptors += suspendFunctionInvokeFunctionDescriptor - overriddenDescriptors += functionInvokeFunctionDescriptor - isSuspend = true - } - } - - override fun buildIr(): IrSimpleFunction { - val startOffset = irFunction.startOffset - val endOffset = irFunction.endOffset - return IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - symbol = symbol, - returnType = irFunction.returnType - ).apply { - parent = coroutineClass - - valueParameters += parameters - this.createDispatchReceiverParameter() - - val thisReceiver = this.dispatchReceiverParameter!! - - val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) - body = irBuilder.irBlockBody(startOffset, endOffset) { - +irReturn( - irCall(invokeSuspendFunction).apply { - dispatchReceiver = irCall(createFunction).apply { - dispatchReceiver = irGet(thisReceiver) - valueParameters.forEachIndexed { index, parameter -> - putValueArgument(index, irGet(parameter)) - } - putValueArgument(valueParameters.size, - irCall(getContinuation, listOf(returnType))) - } - putValueArgument(0, irSuccess(irGetObject(symbols.unit))) - } + functionParameters.forEachIndexed { index, parameter -> + +irSetField( + irGet(coroutineClassThis), + argumentToPropertiesMap[parameter]!!, + irGet(valueParameters[index]) ) } } } } + private fun buildFactoryConstructor(boundParams: List) = WrappedClassConstructorDescriptor().let { + IrConstructorImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrConstructorSymbolImpl(it), + baseClassConstructor.name, + Visibilities.PUBLIC, + coroutineClass.defaultType, + isInline = false, + isExternal = false, + isPrimary = false + ).apply { + it.bind(this) + parent = coroutineClass + coroutineClass.declarations += this + + boundParams.mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index) + } + + val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) + body = irBuilder.irBlockBody { + +irDelegatingConstructorCall(baseClassConstructor).apply { + putValueArgument(0, irNull()) // Completion. + } + +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, + context.irBuiltIns.unitType) + // Save all arguments to fields. + boundParams.forEachIndexed { index, parameter -> + +irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter]!!, + irGet(valueParameters[index])) + } + } + } + } + + private fun buildCreateMethod(unboundArgs: List, + superFunctionSymbol: IrSimpleFunctionSymbol?, + coroutineConstructor: IrConstructor) = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrSimpleFunctionSymbolImpl(it), + Name.identifier("create"), + Visibilities.PRIVATE, + Modality.FINAL, + coroutineClass.defaultType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + it.bind(this) + parent = coroutineClass + coroutineClass.declarations += this + + (unboundArgs + create1CompletionParameter) + .mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index) + } + + this.createDispatchReceiverParameter() + + superFunctionSymbol?.let { overriddenSymbols += it } + + val thisReceiver = this.dispatchReceiverParameter!! + + val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + +irReturn( + irCall(coroutineConstructor).apply { + var unboundIndex = 0 + val unboundArgsSet = unboundArgs.toSet() + functionParameters.map { + if (unboundArgsSet.contains(it)) + irGet(valueParameters[unboundIndex++]) + else + irGetField(irGet(thisReceiver), argumentToPropertiesMap[it]!!) + }.forEachIndexed { index, argument -> + putValueArgument(index, argument) + } + putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex])) + assert(unboundIndex == valueParameters.size - 1) { + "Not all arguments of are used" + } + }) + } + } + } + + private fun buildInvokeMethod(suspendFunctionInvokeFunctionSymbol: IrSimpleFunctionSymbol, + functionInvokeFunctionSymbol: IrSimpleFunctionSymbol, + createFunction: IrFunction, + invokeSuspendFunction: IrFunction) = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrSimpleFunctionSymbolImpl(it), + Name.identifier("invoke"), + Visibilities.PRIVATE, + Modality.FINAL, + irFunction.returnType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = true + ).apply { + it.bind(this) + parent = coroutineClass + coroutineClass.declarations += this + + createFunction.valueParameters + // Skip completion - invoke() already has it implicitly as a suspend function. + .take(createFunction.valueParameters.size - 1) + .mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index) + } + + this.createDispatchReceiverParameter() + + overriddenSymbols += functionInvokeFunctionSymbol + overriddenSymbols += suspendFunctionInvokeFunctionSymbol + + val thisReceiver = this.dispatchReceiverParameter!! + + val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) + body = irBuilder.irBlockBody(startOffset, endOffset) { + +irReturn( + irCall(invokeSuspendFunction).apply { + dispatchReceiver = irCall(createFunction).apply { + dispatchReceiver = irGet(thisReceiver) + valueParameters.forEachIndexed { index, parameter -> + putValueArgument(index, irGet(parameter)) + } + putValueArgument(valueParameters.size, + irCall(getContinuation, listOf(returnType))) + } + putValueArgument(0, irSuccess(irGetObject(symbols.unit))) + } + ) + } + } + } + private fun addField(name: Name, type: IrType, isMutable: Boolean): IrField = createField( - irFunction.startOffset, - irFunction.endOffset, + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, type, name, isMutable, - DECLARATION_ORIGIN_COROUTINE_IMPL, - coroutineClassDescriptor - ).also { - coroutineClass.addChild(it) - } + coroutineClass + ) - private fun createInvokeSuspendMethodBuilder(invokeSuspendFunction: IrFunction, coroutineClass: IrClass) - = object: SymbolWithIrBuilder() { - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - invokeSuspendFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor) - ) - - override fun doInitialize() { } - - override fun buildIr(): IrSimpleFunction { - val originalBody = irFunction.body!! - val startOffset = irFunction.startOffset - val endOffset = irFunction.endOffset - val function = IrFunctionImpl( - startOffset = startOffset, - endOffset = endOffset, - origin = DECLARATION_ORIGIN_COROUTINE_IMPL, - symbol = symbol, - returnType = context.irBuiltIns.anyNType + private fun buildInvokeSuspendMethod(superInvokeSuspendFunction: IrSimpleFunction, + coroutineClass: IrClass): IrSimpleFunction { + val originalBody = irFunction.body!! + val function = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrSimpleFunctionSymbolImpl(it), + superInvokeSuspendFunction.name, + Visibilities.PRIVATE, + Modality.FINAL, + context.irBuiltIns.anyNType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false ).apply { + it.bind(this) parent = coroutineClass + coroutineClass.declarations += this + + superInvokeSuspendFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter -> + parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index) + } this.createDispatchReceiverParameter() - invokeSuspendFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it -> - it.copy(descriptor.valueParameters[index]) - } + overriddenSymbols += superInvokeSuspendFunction.symbol + } + } + resultArgument = function.valueParameters.single() + + val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) + function.body = irBuilder.irBlockBody(startOffset, endOffset) { + + suspendResult = irVar("suspendResult".synthesizedName, context.irBuiltIns.anyNType, true) + + // Extract all suspend calls to temporaries in order to make correct jumps to them. + originalBody.transformChildrenVoid(ExpressionSlicer(labelField.type)) + + val liveLocals = computeLivenessAtSuspensionPoints(originalBody) + + val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.isVar }.toSet() + val localsMap = immutableLiveLocals.associate { it to irVar(it.name, it.type, true) } + + if (localsMap.isNotEmpty()) + transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them. + + val localToPropertyMap = mutableMapOf() + // TODO: optimize by using the same property for different locals. + liveLocals.values.forEach { scope -> + scope.forEach { + localToPropertyMap.getOrPut(it.symbol) { + addField(it.name, it.type, true) + } + } } - resultArgument = function.valueParameters.single() + originalBody.transformChildrenVoid(object : IrElementTransformerVoid() { - val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) - function.body = irBuilder.irBlockBody(startOffset, endOffset) { + private val thisReceiver = function.dispatchReceiverParameter!! - suspendResult = irVar(IrTemporaryVariableDescriptorImpl( - containingDeclaration = irFunction.descriptor, - name = "suspendResult".synthesizedName, - outType = context.builtIns.nullableAnyType, - isMutable = true) - , context.irBuiltIns.anyNType) + // Replace returns to refer to the new function. + override fun visitReturn(expression: IrReturn): IrExpression { + expression.transformChildrenVoid(this) - // Extract all suspend calls to temporaries in order to make correct jumps to them. - originalBody.transformChildrenVoid(ExpressionSlicer(labelField.type)) - - val liveLocals = computeLivenessAtSuspensionPoints(originalBody) - - val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.descriptor.isVar }.toSet() - val localsMap = immutableLiveLocals.associate { - // TODO: Remove .descriptor as soon as all symbols are bound. - val symbol = IrVariableSymbolImpl( - IrTemporaryVariableDescriptorImpl( - containingDeclaration = irFunction.descriptor, - name = it.descriptor.name, - outType = it.descriptor.type, - isMutable = true) - ) - - val variable = IrVariableImpl( - startOffset = it.startOffset, - endOffset = it.endOffset, - origin = it.origin, - symbol = symbol, - type = it.type - ) - - it.descriptor to variable + return if (expression.returnTargetSymbol != irFunction.symbol) + expression + else + irReturn(expression.value) } - if (localsMap.isNotEmpty()) - transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them. + // Replace function arguments loading with properties reading. + override fun visitGetValue(expression: IrGetValue): IrExpression { + expression.transformChildrenVoid(this) - val localToPropertyMap = mutableMapOf() - // TODO: optimize by using the same property for different locals. - liveLocals.values.forEach { scope -> - scope.forEach { - localToPropertyMap.getOrPut(it.symbol) { - addField(it.descriptor.name, it.type, true) - } - } + val capturedValue = argumentToPropertiesMap[expression.symbol.owner] + ?: return expression + return irGetField(irGet(thisReceiver), capturedValue) } - originalBody.transformChildrenVoid(object : IrElementTransformerVoid() { + // Save/restore state at suspension points. + override fun visitExpression(expression: IrExpression): IrExpression { + expression.transformChildrenVoid(this) - private val thisReceiver = function.dispatchReceiverParameter!! + val suspensionPoint = expression as? IrSuspensionPoint + ?: return expression - // Replace returns to refer to the new function. - override fun visitReturn(expression: IrReturn): IrExpression { - expression.transformChildrenVoid(this) + suspensionPoint.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) - return if (expression.returnTarget != irFunction.descriptor) - expression - else - irReturn(expression.value) - } - - // Replace function arguments loading with properties reading. - override fun visitGetValue(expression: IrGetValue): IrExpression { - expression.transformChildrenVoid(this) - - val capturedValue = argumentToPropertiesMap[expression.descriptor] - ?: return expression - return irGetField(irGet(thisReceiver), capturedValue) - } - - // Save/restore state at suspension points. - override fun visitExpression(expression: IrExpression): IrExpression { - expression.transformChildrenVoid(this) - - val suspensionPoint = expression as? IrSuspensionPoint - ?: return expression - - suspensionPoint.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitCall(expression: IrCall): IrExpression { - expression.transformChildrenVoid(this) - - when (expression.symbol) { - saveState.symbol -> { - val scope = liveLocals[suspensionPoint]!! - return irBlock(expression) { - scope.forEach { - val variable = localsMap[it.descriptor] ?: it - +irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable)) - } - +irSetField( - irGet(thisReceiver), - labelField, - irGet(suspensionPoint.suspensionPointIdParameter) - ) + when (expression.symbol) { + saveState.symbol -> { + val scope = liveLocals[suspensionPoint]!! + return irBlock(expression) { + scope.forEach { + val variable = localsMap[it] ?: it + +irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable)) } + +irSetField( + irGet(thisReceiver), + labelField, + irGet(suspensionPoint.suspensionPointIdParameter) + ) } - restoreState.symbol -> { - val scope = liveLocals[suspensionPoint]!! - return irBlock(expression) { - scope.forEach { - +irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!)) - } + } + restoreState.symbol -> { + val scope = liveLocals[suspensionPoint]!! + return irBlock(expression) { + scope.forEach { + +irSetVar(localsMap[it] + ?: it, irGetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!)) } } } - return expression } - }) + return expression + } + }) - return suspensionPoint - } - }) - val statements = (originalBody as IrBlockBody).statements - +suspendResult - +IrSuspendableExpressionImpl( - startOffset = startOffset, - endOffset = endOffset, - type = context.irBuiltIns.unitType, - suspensionPointId = irGetField(irGet(function.dispatchReceiverParameter!!), labelField), - result = irBlock(startOffset, endOffset) { - +irThrowIfNotNull(irExceptionOrNull(irGet(resultArgument))) // Coroutine might start with an exception. - statements.forEach { +it } - }) - if (irFunction.returnType.isUnit()) - +irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions. - } - return function + return suspensionPoint + } + }) + originalBody.setDeclarationsParent(function) + val statements = (originalBody as IrBlockBody).statements + +suspendResult + +IrSuspendableExpressionImpl( + startOffset, endOffset, + context.irBuiltIns.unitType, + suspensionPointId = irGetField(irGet(function.dispatchReceiverParameter!!), labelField), + result = irBlock(startOffset, endOffset) { + +irThrowIfNotNull(irExceptionOrNull(irGet(resultArgument))) // Coroutine might start with an exception. + statements.forEach { +it } + }) + if (irFunction.returnType.isUnit()) + +irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions. } + return function } - private fun transformVariables(element: IrElement, variablesMap: Map) { + private fun transformVariables(element: IrElement, variablesMap: Map) { element.transformChildrenVoid(object: IrElementTransformerVoid() { override fun visitGetValue(expression: IrGetValue): IrExpression { expression.transformChildrenVoid(this) - val newVariable = variablesMap[expression.symbol.descriptor] + val newVariable = variablesMap[expression.symbol.owner] ?: return expression return IrGetValueImpl( @@ -886,7 +732,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass override fun visitSetVariable(expression: IrSetVariable): IrExpression { expression.transformChildrenVoid(this) - val newVariable = variablesMap[expression.symbol.descriptor] + val newVariable = variablesMap[expression.symbol.owner] ?: return expression return IrSetVariableImpl( @@ -901,7 +747,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass override fun visitVariable(declaration: IrVariable): IrStatement { declaration.transformChildrenVoid(this) - val newVariable = variablesMap[declaration.symbol.descriptor] + val newVariable = variablesMap[declaration] ?: return declaration newVariable.initializer = declaration.initializer @@ -929,33 +775,49 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass val visibleVariables = mutableListOf() scopeStack.forEach { visibleVariables += it } - result.put(suspensionPoint, visibleVariables) + result[suspensionPoint] = visibleVariables } }) return result } - // These are marker descriptors to split up the lowering on two parts. - private val saveState = IrFunctionImpl(irFunction.startOffset, irFunction.startOffset, IrDeclarationOrigin.DEFINED, - SimpleFunctionDescriptorImpl.create( - irFunction.descriptor, - Annotations.EMPTY, - "saveState".synthesizedName, - CallableMemberDescriptor.Kind.SYNTHESIZED, - SourceElement.NO_SOURCE).apply { - initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) - }, context.irBuiltIns.unitType) + // These are marker functions to split up the lowering on two parts. + private val saveState = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(it), + "saveState".synthesizedName, + Visibilities.PRIVATE, + Modality.ABSTRACT, + context.irBuiltIns.unitType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + it.bind(this) + } + } - private val restoreState = IrFunctionImpl(irFunction.startOffset, irFunction.startOffset, IrDeclarationOrigin.DEFINED, - SimpleFunctionDescriptorImpl.create( - irFunction.descriptor, - Annotations.EMPTY, - "restoreState".synthesizedName, - CallableMemberDescriptor.Kind.SYNTHESIZED, - SourceElement.NO_SOURCE).apply { - initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) - }, context.irBuiltIns.unitType) + private val restoreState = WrappedSimpleFunctionDescriptor().let { + IrFunctionImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(it), + "restoreState".synthesizedName, + Visibilities.PRIVATE, + Modality.ABSTRACT, + context.irBuiltIns.unitType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + it.bind(this) + } + } private inner class ExpressionSlicer(val suspensionPointIdType: IrType): IrElementTransformerVoid() { // TODO: optimize - it has square complexity. @@ -979,7 +841,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass is IrSetField -> listOf(expression.receiver, expression.value) is IrMemberAccessExpression -> ( listOf(expression.dispatchReceiver, expression.extensionReceiver) - + expression.descriptor.valueParameters.map { expression.getValueArgument(it.index) } + + (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it) } ) else -> throw Error("Unexpected expression: $expression") } @@ -1072,15 +934,14 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass if (suspendCall == null) return irWrap(expression, tempStatements) - val suspensionPointIdParameter = IrTemporaryVariableDescriptorImpl( - containingDeclaration = irFunction.descriptor, - name = "suspensionPointId${suspensionPointIdIndex++}".synthesizedName, - outType = suspensionPointIdType.toKotlinType()) val suspensionPoint = IrSuspensionPointImpl( startOffset = startOffset, endOffset = endOffset, type = context.irBuiltIns.anyNType, - suspensionPointIdParameter = irVar(suspensionPointIdParameter, suspensionPointIdType), + suspensionPointIdParameter = irVar( + "suspensionPointId${suspensionPointIdIndex++}".synthesizedName, + suspensionPointIdType + ), result = irBlock(startOffset, endOffset) { if (!calledSaveState) +irCall(saveState) @@ -1113,7 +974,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass } private val IrExpression.isSuspendCall: Boolean - get() = this is IrCall && this.descriptor.isSuspend + get() = this is IrCall && this.symbol.owner.isSuspend private fun IrElement.isSpecialBlock() = this is IrBlock && this.origin == STATEMENT_ORIGIN_COROUTINE_IMPL @@ -1144,27 +1005,36 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass is IrConst<*> -> true is IrCall -> false // TODO: skip builtin operators. is IrTypeOperatorCall -> this.argument.isPure() && this.operator != IrTypeOperator.CAST - is IrGetValue -> !this.descriptor.let { it is VariableDescriptor && it.isVar } + is IrGetValue -> !this.symbol.owner.let { it is IrVariable && it.isVar } else -> false } } private val IrExpression.isReturnIfSuspendedCall: Boolean - get() = this is IrCall && this.descriptor.original == returnIfSuspendedDescriptor + get() = this is IrCall && this.symbol == returnIfSuspended } private fun IrBuilderWithScope.irVar(initializer: IrExpression) = - irVar( - IrTemporaryVariableDescriptorImpl( - containingDeclaration = irFunction.descriptor, - name = "tmp${tempIndex++}".synthesizedName, - outType = initializer.type.toKotlinType() - ), - initializer.type - ).apply { this.initializer = initializer } + irVar("tmp${tempIndex++}".synthesizedName, initializer.type, false, initializer) - private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, type: IrType) = - IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, type) + private fun IrBuilderWithScope.irVar(name: Name, type: IrType, + isMutable: Boolean = false, + initializer: IrExpression? = null) = WrappedVariableDescriptor().let { + IrVariableImpl( + startOffset, endOffset, + DECLARATION_ORIGIN_COROUTINE_IMPL, + IrVariableSymbolImpl(it), + name, + type, + isMutable, + isConst = false, + isLateinit = false + ).apply { + it.bind(this) + this.initializer = initializer + this.parent = this@irVar.parent + } + } private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueDeclaration) = irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt index fe70ffa0629..bff67588adf 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt @@ -5,47 +5,38 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.descriptors.replace -import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor -import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope -import org.jetbrains.kotlin.backend.common.lower.SymbolWithIrBuilder +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.reportWarning import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName +import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.backend.konan.reportCompilationError -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.isFunctionType 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.ClassDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal class TestProcessor (val context: KonanBackendContext) { @@ -60,72 +51,65 @@ internal class TestProcessor (val context: KonanBackendContext) { val IGNORE_FQ_NAME = FqName.fromSegments(listOf("kotlin", "test" , "Ignore")) } - val symbols = context.ir.symbols + private val symbols = context.ir.symbols - val baseClassSuiteDescriptor = symbols.baseClassSuite.descriptor + private val baseClassSuite = symbols.baseClassSuite.owner private val topLevelSuiteNames = mutableSetOf() // region Useful extensions. - var testSuiteCnt = 0 - fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName() - fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName + private var testSuiteCnt = 0 + private fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName() + private fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName // IrFile always uses a forward slash as a directory separator. private val IrFile.fileName get() = name.substringAfterLast('/') + private val IrFile.topLevelSuiteName: String get() { - val packageFqName = packageFragmentDescriptor.fqName + val packageFqName = fqName val shortFileName = PackagePartClassUtils.getFilePartShortName(fileName) return if (packageFqName.isRoot) shortFileName else "$packageFqName.$shortFileName" } private fun MutableList.registerFunction( - function: IrFunctionSymbol, + function: IrFunction, kinds: Collection>) = kinds.forEach { (kind, ignored) -> add(TestFunction(function, kind, ignored)) } private fun MutableList.registerFunction( - function: IrFunctionSymbol, + function: IrFunction, kind: FunctionKind, ignored: Boolean ) = add(TestFunction(function, kind, ignored)) private fun IrStatementsBuilder.generateFunctionRegistration( receiver: IrValueDeclaration, - registerTestCase: IrFunctionSymbol, - registerFunction: IrFunctionSymbol, + registerTestCase: IrFunction, + registerFunction: IrFunction, functions: Collection) { functions.forEach { if (it.kind == FunctionKind.TEST) { // Call registerTestCase(name: String, testFunction: () -> Unit) method. - +irCall(registerTestCase, registerTestCase.descriptor.returnType!!.toErasedIrType()).apply { + +irCall(registerTestCase).apply { dispatchReceiver = irGet(receiver) - putValueArgument(0, IrConstImpl.string( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - context.irBuiltIns.stringType, - it.function.descriptor.name.identifier) - ) + putValueArgument(0, irString(it.function.name.identifier)) putValueArgument(1, IrFunctionReferenceImpl( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - descriptor.valueParameters[1].type.toErasedIrType(), - it.function, - it.function.descriptor, 0)) - putValueArgument(2, IrConstImpl.boolean( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - context.irBuiltIns.booleanType, - it.ignored - )) + registerTestCase.valueParameters[1].type, + it.function.symbol, + it.function.descriptor, + typeArgumentsCount = 0, + valueArgumentsCount = 0)) + putValueArgument(2, irBoolean(it.ignored)) } } else { // Call registerFunction(kind: TestFunctionKind, () -> Unit) method. - +irCall(registerFunction, registerFunction.descriptor.returnType!!.toErasedIrType()).apply { + +irCall(registerFunction).apply { dispatchReceiver = irGet(receiver) val testKindEntry = it.kind.runtimeKind putValueArgument(0, IrGetEnumValueImpl( @@ -134,12 +118,13 @@ internal class TestProcessor (val context: KonanBackendContext) { symbols.testFunctionKind.typeWithoutArguments, testKindEntry) ) - putValueArgument(1, IrFunctionReferenceImpl( + putValueArgument(1, IrFunctionReferenceImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - descriptor.valueParameters[1].type.toErasedIrType(), - it.function, - it.function.descriptor, 0)) + registerFunction.valueParameters[1].type, + it.function.symbol, + it.function.descriptor, + typeArgumentsCount = 0, + valueArgumentsCount = 0)) } } } @@ -149,7 +134,7 @@ internal class TestProcessor (val context: KonanBackendContext) { // region Classes for annotation collection. internal enum class FunctionKind(annotationNameString: String, runtimeKindString: String) { TEST("kotlin.test.Test", "") { - override val runtimeKindName: Name get() = throw NotImplementedError() + override val runtimeKindName: Name get() = throw NotImplementedError() }, BEFORE_EACH("kotlin.test.BeforeEach", "BEFORE_EACH"), @@ -169,34 +154,34 @@ internal class TestProcessor (val context: KonanBackendContext) { private val FunctionKind.runtimeKind: IrEnumEntrySymbol get() = symbols.getTestFunctionKind(this) + private fun IrType.isTestFunctionKind() = classifierOrNull == symbols.testFunctionKind + private data class TestFunction( - val function: IrFunctionSymbol, + val function: IrFunction, val kind: FunctionKind, val ignored: Boolean ) - private inner class TestClass(val ownerClass: IrClassSymbol) { - var companion: IrClassSymbol? = null + private inner class TestClass(val ownerClass: IrClass) { + var companion: IrClass? = null val functions = mutableListOf() fun registerFunction( - function: IrFunctionSymbol, + function: IrFunction, kinds: Collection> ) = functions.registerFunction(function, kinds) - fun registerFunction(function: IrFunctionSymbol, kind: FunctionKind, ignored: Boolean) = + + fun registerFunction(function: IrFunction, kind: FunctionKind, ignored: Boolean) = functions.registerFunction(function, kind, ignored) } private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid { - val testClasses = mutableMapOf() + val testClasses = mutableMapOf() val topLevelFunctions = mutableListOf() - private fun MutableMap.getTestClass(key: IrClassSymbol) = + private fun MutableMap.getTestClass(key: IrClass) = getOrPut(key) { TestClass(key) } - private fun MutableMap.getTestClass(key: ClassDescriptor) = - getTestClass(symbols.symbolTable.referenceClass(key)) - override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } @@ -227,45 +212,50 @@ internal class TestProcessor (val context: KonanBackendContext) { } } - fun registerClassFunction(classDescriptor: ClassDescriptor, - function: IrFunctionSymbol, + fun registerClassFunction(irClass: IrClass, + function: IrFunction, kinds: Collection>) { - fun warn(msg: String) = context.reportWarning(msg, irFile, function.owner) + fun warn(msg: String) = context.reportWarning(msg, irFile, function) kinds.forEach { (kind, ignored) -> val annotation = kind.annotationFqName when (kind) { - in FunctionKind.INSTANCE_KINDS -> with(classDescriptor) { + in FunctionKind.INSTANCE_KINDS -> with(irClass) { when { isInner -> warn("Annotation $annotation is not allowed for methods of an inner class") + isAbstract() -> { // We cannot create an abstract test class but it's allowed to mark its methods as // tests because the class can be extended. So skip this case without warnings. } - isCompanionObject -> + + isCompanion -> warn("Annotation $annotation is not allowed for methods of a companion object") + constructors.none { it.valueParameters.size == 0 } -> - warn("Test class has no default constructor: ${fqNameSafe}") + warn("Test class has no default constructor: $fqNameSafe") + else -> - testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored) + testClasses.getTestClass(irClass).registerFunction(function, kind, ignored) } } in FunctionKind.COMPANION_KINDS -> when { - classDescriptor.isCompanionObject -> { - val containingClass = classDescriptor.containingDeclaration as ClassDescriptor + irClass.isCompanion -> { + val containingClass = irClass.parentAsClass val testClass = testClasses.getTestClass(containingClass) - testClass.companion = symbols.symbolTable.referenceClass(classDescriptor) + testClass.companion = irClass testClass.registerFunction(function, kind, ignored) } - classDescriptor.kind == ClassKind.OBJECT -> { - testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored) + + irClass.kind == ClassKind.OBJECT -> { + testClasses.getTestClass(irClass).registerFunction(function, kind, ignored) } + else -> warn("Annotation $annotation is only allowed for methods of an object " + "(named or companion) or top level functions") - } else -> throw IllegalStateException("Unreachable") } @@ -274,14 +264,14 @@ internal class TestProcessor (val context: KonanBackendContext) { fun IrFunction.checkFunctionSignature() { // Test runner requires test functions to have the following signature: () -> Unit. - if (descriptor.returnType != context.builtIns.unitType) { + if (!returnType.isUnit()) { context.reportCompilationError( - "Test function must return Unit: ${descriptor.fqNameSafe}", irFile, this + "Test function must return Unit: $fqNameSafe", irFile, this ) } - if (descriptor.valueParameters.isNotEmpty()) { + if (valueParameters.isNotEmpty()) { context.reportCompilationError( - "Test function must have no arguments: ${descriptor.fqNameSafe}", irFile, this + "Test function must have no arguments: $fqNameSafe", irFile, this ) } } @@ -314,7 +304,7 @@ internal class TestProcessor (val context: KonanBackendContext) { // TODO: Use symbols instead of containingDeclaration when such information is available. override fun visitFunction(declaration: IrFunction) { val symbol = declaration.symbol - val owner = declaration.descriptor.containingDeclaration + val parent = declaration.parent warnAboutLoneIgnore(symbol) val kinds = FunctionKind.values().mapNotNull { kind -> @@ -329,10 +319,10 @@ internal class TestProcessor (val context: KonanBackendContext) { } declaration.checkFunctionSignature() - when (owner) { - is PackageFragmentDescriptor -> topLevelFunctions.registerFunction(symbol, kinds) - is ClassDescriptor -> registerClassFunction(owner, symbol, kinds) - else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $owner") + when (parent) { + is IrPackageFragment -> topLevelFunctions.registerFunction(declaration, kinds) + is IrClass -> registerClassFunction(parent, declaration, kinds) + else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $parent") } } } @@ -340,60 +330,36 @@ internal class TestProcessor (val context: KonanBackendContext) { //region Symbol and IR builders - /** Base class for getters (createInstance and getCompanion). */ - private abstract inner class GetterBuilder(val returnType: IrType, - val testSuite: IrClassSymbol, - val getterName: Name) - : SymbolWithIrBuilder() { - - val superFunction = baseClassSuiteDescriptor - .unsubstitutedMemberScope - .getContributedFunctions(getterName, NoLookupLocation.FROM_BACKEND) - .single { it.valueParameters.isEmpty() } - - - override fun doInitialize() { - val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - descriptor.initialize( - /* receiverParameterType = */ null, - /* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter, - /* typeParameters = */ emptyList(), - /* unsubstitutedValueParameters = */ emptyList(), - /* returnType = */ returnType.toKotlinType(), - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PROTECTED - ).apply { - overriddenDescriptors += superFunction - } - } - - override fun buildSymbol() = IrSimpleFunctionSymbolImpl( - SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ testSuite.descriptor, - /* annotations = */ Annotations.EMPTY, - /* name = */ getterName, - /* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED, - /* source = */ SourceElement.NO_SOURCE - ) - ) - } - /** - * Builds a method in `[testSuite]` class with name `[getterName]` + * Builds a method in `[owner]` class with name `[getterName]` * returning a reference to an object represented by `[objectSymbol]`. */ - private inner class ObjectGetterBuilder(val objectSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name) - : GetterBuilder(objectSymbol.typeWithoutArguments, testSuite, getterName) { - - override fun buildIr(): IrFunction = IrFunctionImpl( + private fun buildObjectGetter(objectSymbol: IrClassSymbol, + owner: IrClass, + getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor -> + IrFunctionImpl( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, TEST_SUITE_GENERATED_MEMBER, - symbol, - this@ObjectGetterBuilder.returnType + IrSimpleFunctionSymbolImpl(descriptor), + getterName, + Visibilities.PROTECTED, + Modality.FINAL, + objectSymbol.typeWithStarProjections, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false ).apply { - val builder = context.createIrBuilder(symbol) - createParameterDeclarations(context.ir.symbols.symbolTable) - body = builder.irBlockBody { + descriptor.bind(this) + parent = owner + + val superFunction = baseClassSuite.simpleFunctions() + .single { it.name == getterName && it.valueParameters.isEmpty() } + + createDispatchReceiverParameter() + overriddenSymbols += superFunction.symbol + + body = context.createIrBuilder(symbol).irBlockBody { +irReturn(IrGetObjectValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, objectSymbol.typeWithoutArguments, objectSymbol) ) @@ -405,234 +371,202 @@ internal class TestProcessor (val context: KonanBackendContext) { * Builds a method in `[testSuite]` class with name `[getterName]` * returning a new instance of class referenced by [classSymbol]. */ - private inner class InstanceGetterBuilder(val classSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name) - : GetterBuilder(classSymbol.typeWithStarProjections, testSuite, getterName) { - - override fun buildIr() = IrFunctionImpl( + private fun buildInstanceGetter(classSymbol: IrClassSymbol, + owner: IrClass, + getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor -> + IrFunctionImpl( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, TEST_SUITE_GENERATED_MEMBER, - symbol, - this@InstanceGetterBuilder.returnType + IrSimpleFunctionSymbolImpl(descriptor), + getterName, + Visibilities.PROTECTED, + Modality.FINAL, + classSymbol.typeWithStarProjections, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false ).apply { - val builder = context.createIrBuilder(symbol) - createParameterDeclarations(context.ir.symbols.symbolTable) - body = builder.irBlockBody { + descriptor.bind(this) + parent = owner + + val superFunction = baseClassSuite.simpleFunctions() + .single { it.name == getterName && it.valueParameters.isEmpty() } + + createDispatchReceiverParameter() + overriddenSymbols += superFunction.symbol + + body = context.createIrBuilder(symbol).irBlockBody { val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() } +irReturn(irCall(constructor)) } } } + private val baseClassSuiteConstructor = baseClassSuite.constructors.single { + it.valueParameters.size == 2 + && it.valueParameters[0].type.isString() // name: String + && it.valueParameters[1].type.isBoolean() // ignored: Boolean + } + /** * Builds a constructor for a test suite class representing a test class (any class in the original IrFile with * method(s) annotated with @Test). The test suite class is a subclass of ClassTestSuite * where T is the test class. */ - private inner class ClassSuiteConstructorBuilder(val suiteName: String, - val testClassType: KotlinType, - val testCompanionType: KotlinType, - val testSuite: IrClassSymbol, - val functions: Collection, - val ignored: Boolean) - : SymbolWithIrBuilder() { - - private fun IrClassSymbol.getFunction(name: String, predicate: (FunctionDescriptor) -> Boolean) = - symbols.symbolTable.referenceFunction(descriptor.unsubstitutedMemberScope - .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND) - .single(predicate)) - - override fun buildIr() = IrConstructorImpl( + private fun buildClassSuiteConstructor(suiteName: String, + testClassType: IrType, + testCompanionType: IrType, + testSuite: IrClassSymbol, + owner: IrClass, + functions: Collection, + ignored: Boolean) = WrappedClassConstructorDescriptor().let { descriptor -> + IrConstructorImpl( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, TEST_SUITE_GENERATED_MEMBER, - symbol, - testSuite.typeWithStarProjections + IrConstructorSymbolImpl(descriptor), + Name.special(""), + Visibilities.PUBLIC, + testSuite.typeWithStarProjections, + isInline = false, + isExternal = false, + isPrimary = true ).apply { + descriptor.bind(this) + parent = owner - createParameterDeclarations(context.ir.symbols.symbolTable) + fun IrClass.getFunction(name: String, predicate: (IrSimpleFunction) -> Boolean) = + simpleFunctions().single { it.name.asString() == name && predicate(it) } - val registerTestCase = symbols.baseClassSuite.getFunction("registerTestCase") { - it.valueParameters.size == 3 && - KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String - it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit - KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean + val registerTestCase = baseClassSuite.getFunction("registerTestCase") { + it.valueParameters.size == 3 + && it.valueParameters[0].type.isString() // name: String + && it.valueParameters[1].type.isFunction() // function: testClassType.() -> Unit + && it.valueParameters[2].type.isBoolean() // ignored: Boolean } - val registerFunction = symbols.baseClassSuite.getFunction("registerFunction") { - it.valueParameters.size == 2 && - it.valueParameters[0].type == symbols.testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind - it.valueParameters[1].type.isFunctionType // function: () -> Unit + val registerFunction = baseClassSuite.getFunction("registerFunction") { + it.valueParameters.size == 2 + && it.valueParameters[0].type.isTestFunctionKind() // kind: TestFunctionKind + && it.valueParameters[1].type.isFunction() // function: () -> Unit } body = context.createIrBuilder(symbol).irBlockBody { - val superConstructor = symbols.baseClassSuiteConstructor - +IrDelegatingConstructorCallImpl( - startOffset = SYNTHETIC_OFFSET, - endOffset = SYNTHETIC_OFFSET, - type = context.irBuiltIns.unitType, - symbol = symbols.symbolTable.referenceConstructor(superConstructor), - descriptor = superConstructor, - typeArgumentsCount = 2 - ).apply { - putTypeArgument(0, testClassType.toErasedIrType()) - putTypeArgument(1, testCompanionType.toErasedIrType()) + +irDelegatingConstructorCall(baseClassSuiteConstructor).apply { + putTypeArgument(0, testClassType) + putTypeArgument(1, testCompanionType) - putValueArgument(0, IrConstImpl.string( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - context.irBuiltIns.stringType, - suiteName) - ) - putValueArgument(1, IrConstImpl.boolean( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - context.irBuiltIns.booleanType, - ignored - )) + putValueArgument(0, irString(suiteName)) + putValueArgument(1, irBoolean(ignored)) } generateFunctionRegistration(testSuite.owner.thisReceiver!!, registerTestCase, registerFunction, functions) } } - - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl - descriptor.initialize(emptyList(), Visibilities.PUBLIC).apply { - returnType = testSuite.descriptor.defaultType - } - } - - override fun buildSymbol() = IrConstructorSymbolImpl( - ClassConstructorDescriptorImpl.createSynthesized( - testSuite.descriptor, - Annotations.EMPTY, - true, - SourceElement.NO_SOURCE - ) - ) } - private fun KotlinType.toErasedIrType(): IrType = context.ir.translateErased(this) + private val IrClass.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME) /** * Builds a test suite class representing a test class (any class in the original IrFile with method(s) * annotated with @Test). The test suite class is a subclass of ClassTestSuite where T is the test class. */ - private inner class ClassSuiteBuilder(testClass: IrClassSymbol, - testCompanion: IrClassSymbol?, - val containingDeclaration: DeclarationDescriptor, - val functions: Collection) - : SymbolWithIrBuilder() { - - private val IrClassSymbol.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME) - private val IrClassSymbol.isObject: Boolean get() = descriptor.kind == ClassKind.OBJECT - - val suiteName = testClass.descriptor.fqNameSafe.toString() - val suiteClassName = testClass.descriptor.name.synthesizeSuiteClassName() - - val testClassType = testClass.descriptor.defaultType - val testCompanionType = if (testClass.isObject) { - testClassType - } else { - testCompanion?.descriptor?.defaultType ?: context.irBuiltIns.nothing - } - - val superType = baseClassSuiteDescriptor.defaultType.replace(listOf(testClassType, testCompanionType)) - - val constructorBuilder = ClassSuiteConstructorBuilder( - suiteName, testClassType, testCompanionType, symbol, functions, testClass.ignored - ) - - val instanceGetterBuilder: GetterBuilder - val companionGetterBuilder: GetterBuilder? - - init { - if (testClass.isObject) { - instanceGetterBuilder = ObjectGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME) - companionGetterBuilder = ObjectGetterBuilder(testClass, symbol, COMPANION_GETTER_NAME) - } else { - instanceGetterBuilder = InstanceGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME) - companionGetterBuilder = testCompanion?.let { - ObjectGetterBuilder(it, symbol, COMPANION_GETTER_NAME) - } - } - } - - override fun buildIr() = symbols.symbolTable.declareClass( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, + private fun buildClassSuite(testClass: IrClass, + testCompanion: IrClass?, + functions: Collection) = WrappedClassDescriptor().let { descriptor -> + IrClassImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, TEST_SUITE_CLASS, - symbol.descriptor).apply { + IrClassSymbolImpl(descriptor), + testClass.name.synthesizeSuiteClassName(), + ClassKind.CLASS, + Visibilities.PRIVATE, + Modality.FINAL, + isCompanion = false, + isInner = false, + isData = false, + isExternal = false, + isInline = false + ).apply { + descriptor.bind(this) createParameterDeclarations() - addMember(constructorBuilder.ir) - addMember(instanceGetterBuilder.ir) - companionGetterBuilder?.let { addMember(it.ir) } - addFakeOverrides(symbols.symbolTable) - setSuperSymbols(symbols.symbolTable) - } - override fun doInitialize() { - val descriptor = symbol.descriptor as ClassDescriptorImpl - val constructorDescriptor = constructorBuilder.symbol.descriptor + val testClassType = testClass.defaultType + val testCompanionType = if (testClass.kind == ClassKind.OBJECT) { + testClassType + } else { + testCompanion?.defaultType ?: context.irBuiltIns.nothingType + } - val contributedDescriptors = baseClassSuiteDescriptor - .unsubstitutedMemberScope - .getContributedDescriptors() - .map { - when { - it == instanceGetterBuilder.superFunction -> instanceGetterBuilder.symbol.descriptor - it == companionGetterBuilder?.superFunction -> companionGetterBuilder.symbol.descriptor - else -> it.createFakeOverrideDescriptor(symbol.descriptor as ClassDescriptorImpl) - } - }.filterNotNull() - - descriptor.initialize( - SimpleMemberScope(contributedDescriptors),setOf(constructorDescriptor), constructorDescriptor + val constructor = buildClassSuiteConstructor( + testClass.fqNameSafe.toString(), testClassType, testCompanionType, + symbol, this, functions, testClass.ignored ) - constructorBuilder.initialize() - instanceGetterBuilder.initialize() - companionGetterBuilder?.initialize() - } + val instanceGetter: IrFunction + val companionGetter: IrFunction? - override fun buildSymbol() = symbols.symbolTable.referenceClass( - ClassDescriptorImpl( - /* containingDeclaration = */ containingDeclaration, - /* name = */ suiteClassName, - /* modality = */ Modality.FINAL, - /* kind = */ ClassKind.CLASS, - /* superTypes = */ listOf(superType), - /* source = */ SourceElement.NO_SOURCE, - /* isExternal = */ false, - /* storageManager = */ LockBasedStorageManager.NO_LOCKS - ) - ) + if (testClass.kind == ClassKind.OBJECT) { + instanceGetter = buildObjectGetter(testClass.symbol, this, INSTANCE_GETTER_NAME) + companionGetter = buildObjectGetter(testClass.symbol, this, COMPANION_GETTER_NAME) + } else { + instanceGetter = buildInstanceGetter(testClass.symbol, this, INSTANCE_GETTER_NAME) + companionGetter = testCompanion?.let { + buildObjectGetter(it.symbol, this, COMPANION_GETTER_NAME) + } + } + + declarations += constructor + declarations += instanceGetter + companionGetter?.let { declarations += it } + + superTypes += symbols.baseClassSuite.typeWith(listOf(testClassType, testCompanionType)) + addFakeOverrides() + } } //endregion // region IR generation methods private fun generateClassSuite(irFile: IrFile, testClass: TestClass) = - with(ClassSuiteBuilder(testClass.ownerClass, - testClass.companion, - irFile.packageFragmentDescriptor, - testClass.functions)) { - initialize() - irFile.addChild(ir) - val irConstructor = ir.constructors.single() - irFile.addTopLevelInitializer( - IrCallImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, irConstructor.returnType, irConstructor.symbol), - context, threadLocal = true) + with(buildClassSuite(testClass.ownerClass, testClass.companion,testClass.functions)) { + irFile.addChild(this) + val irConstructor = constructors.single() + context.createIrBuilder(irFile.symbol).run { + irFile.addTopLevelInitializer( + irCall(irConstructor), + this@TestProcessor.context, + threadLocal = true) + } } /** Check if this fqName already used or not. */ private fun checkSuiteName(irFile: IrFile, name: String): Boolean { if (topLevelSuiteNames.contains(name)) { - context.reportCompilationError("Package '${irFile.packageFragmentDescriptor.fqName}' has top-level test " + + context.reportCompilationError("Package '${irFile.fqName}' has top-level test " + "functions in several files with the same name: '${irFile.fileName}'") - return false } topLevelSuiteNames.add(name) return true } + private val topLevelSuite = symbols.topLevelSuite.owner + private val topLevelSuiteConstructor = topLevelSuite.constructors.single { + it.valueParameters.size == 1 + && it.valueParameters[0].type.isString() + } + private val topLevelSuiteRegisterFunction = topLevelSuite.simpleFunctions().single { + it.name.asString() == "registerFunction" + && it.valueParameters.size == 2 + && it.valueParameters[0].type.isTestFunctionKind() + && it.valueParameters[1].type.isFunction() + } + private val topLevelSuiteRegisterTestCase = topLevelSuite.simpleFunctions().single { + it.name.asString() == "registerTestCase" + && it.valueParameters.size == 3 + && it.valueParameters[0].type.isString() + && it.valueParameters[1].type.isFunction() + && it.valueParameters[2].type.isBoolean() + } + private fun generateTopLevelSuite(irFile: IrFile, functions: Collection) { val builder = context.createIrBuilder(irFile.symbol) val suiteName = irFile.topLevelSuiteName @@ -643,14 +577,14 @@ internal class TestProcessor (val context: KonanBackendContext) { // TODO: an awful hack, we make this initializer thread local, so that it doesn't freeze suite, // and later on we could modify some suite's properties. This shall be redesigned. irFile.addTopLevelInitializer(builder.irBlock { - val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply { + val constructorCall = irCall(topLevelSuiteConstructor).apply { putValueArgument(0, IrConstImpl.string(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.irBuiltIns.stringType, suiteName)) } val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite") generateFunctionRegistration(testSuiteVal, - symbols.topLevelSuiteRegisterTestCase, - symbols.topLevelSuiteRegisterFunction, + topLevelSuiteRegisterTestCase, + topLevelSuiteRegisterFunction, functions) }, context, threadLocal = true) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VarargLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VarargLowering.kt index a2cd2613a52..278eec500d0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VarargLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VarargLowering.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.ir.IrElement @@ -38,7 +39,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.util.OperatorNameConventions - class VarargInjectionLowering constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass { override fun lower(irDeclarationContainer: IrDeclarationContainer) { irDeclarationContainer.declarations.forEach{ @@ -99,63 +99,53 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De override fun visitVararg(expression: IrVararg): IrExpression { expression.transformChildrenVoid(transformer) + val hasSpreadElement = hasSpreadElement(expression) val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset) - irBuilder.run { + return irBuilder.irBlock(expression, null, expression.type) { val type = expression.varargElementType log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" } val arrayHandle = arrayType(expression.type) - val block = irBlock(expression.type) val vars = expression.elements.map { - val initVar = scope.createTemporaryVariable( - (it as? IrSpreadElement)?.expression ?: it as IrExpression, - "elem".synthesizedString, true) - block.statements.add(initVar) - it to initVar + it to irTemporaryVar( + (it as? IrSpreadElement)?.expression ?: it as IrExpression, + "elem".synthesizedString + ) }.toMap() val arraySize = calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars) val array = arrayHandle.createArray(this, expression.varargElementType, arraySize) - val arrayTmpVariable = scope.createTemporaryVariable(array, "array".synthesizedString, true) - val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "index".synthesizedString, true) - block.statements.add(arrayTmpVariable) - if (hasSpreadElement) { - block.statements.add(indexTmpVariable) - } + val arrayTmpVariable = irTemporaryVar(array, "array".synthesizedString) + lateinit var indexTmpVariable: IrVariable + if (hasSpreadElement) + indexTmpVariable = irTemporaryVar(kIntZero, "index".synthesizedString) expression.elements.forEachIndexed { i, element -> - irBuilder.startOffset = element.startOffset - irBuilder.endOffset = element.endOffset - irBuilder.apply { - log { "element:$i> ${ir2string(element)}" } - val dst = vars[element]!! - if (element !is IrSpreadElement) { - val setArrayElementCall = irCall(arrayHandle.setMethodSymbol.owner) - setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable) - setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i)) - setArrayElementCall.putValueArgument(1, irGet(dst)) - block.statements.add(setArrayElementCall) - if (hasSpreadElement) { - block.statements.add(incrementVariable(indexTmpVariable, kIntOne)) - } - } else { - val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString) - block.statements.add(arraySizeVariable) - val copyCall = irCall(arrayHandle.copyRangeToSymbol.owner).apply { - extensionReceiver = irGet(dst) - putValueArgument(0, irGet(arrayTmpVariable)) /* destination */ - putValueArgument(1, kIntZero) /* fromIndex */ - putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */ - putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */ - } - block.statements.add(copyCall) - block.statements.add(incrementVariable(indexTmpVariable, irGet(arraySizeVariable))) - log { "element:$i:spread element> ${ir2string(element.expression)}" } + irBuilder.at(element.startOffset, element.endOffset) + log { "element:$i> ${ir2string(element)}" } + val dst = vars[element]!! + if (element !is IrSpreadElement) { + +irCall(arrayHandle.setMethodSymbol.owner).apply { + dispatchReceiver = irGet(arrayTmpVariable) + putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i)) + putValueArgument(1, irGet(dst)) } + if (hasSpreadElement) + +incrementVariable(indexTmpVariable, kIntOne) + } else { + val arraySizeVariable = irTemporary(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString) + +irCall(arrayHandle.copyRangeToSymbol.owner).apply { + extensionReceiver = irGet(dst) + putValueArgument(0, irGet(arrayTmpVariable)) /* destination */ + putValueArgument(1, kIntZero) /* fromIndex */ + putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */ + putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */ + } + +incrementVariable(indexTmpVariable, irGet(arraySizeVariable)) + log { "element:$i:spread element> ${ir2string(element.expression)}" } } } - block.statements.add(irGet(arrayTmpVariable)) - return block + +irGet(arrayTmpVariable) } } }) @@ -273,6 +263,5 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De private fun IrBuilderWithScope.irConstInt(value: Int): IrConst = IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, value) -private fun IrBuilderWithScope.irBlock(type: IrType): IrBlock = IrBlockImpl(startOffset, endOffset, type) private val IrBuilderWithScope.kIntZero get() = irConstInt(0) private val IrBuilderWithScope.kIntOne get() = irConstInt(1) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/loops/HeaderProcessor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/loops/HeaderProcessor.kt index b3d4fc371db..0741be2f16c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/loops/HeaderProcessor.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/loops/HeaderProcessor.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt index e833813e149..c71f4250c88 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt @@ -37,7 +37,7 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid override fun visitClass(declaration: IrClass) { if (declaration.isInner) - declaration.addChild(context.specialDeclarationsFactory.getOuterThisField(declaration)) + declaration.declarations += context.specialDeclarationsFactory.getOuterThisField(declaration) // Mark all dangling fields (they are created when class is inherited via delegation). declaration.declarations.filterIsInstance().forEach { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt index 0061201d650..169e04e76e0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt @@ -6,22 +6,21 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.descriptors.substitute +import org.jetbrains.kotlin.backend.common.descriptors.* +import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* @@ -30,14 +29,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.OverridingStrategy -import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.KotlinType @@ -50,38 +50,29 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC private var topLevelInitializersCounter = 0 internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) { - val fieldDescriptor = PropertyDescriptorImpl.create( - this.packageFragmentDescriptor, + val descriptor = WrappedFieldDescriptor( if (threadLocal) Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType, emptyMap(), SourceElement.NO_SOURCE))) else - Annotations.EMPTY, - Modality.FINAL, - Visibilities.PRIVATE, - false, - "topLevelInitializer${topLevelInitializersCounter++}".synthesizedName, - CallableMemberDescriptor.Kind.DECLARATION, - SourceElement.NO_SOURCE, - false, - false, - false, - false, - false, - false + Annotations.EMPTY ) - - fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null) - fieldDescriptor.initialize(null, null) - val irField = IrFieldImpl( expression.startOffset, expression.endOffset, - IrDeclarationOrigin.DEFINED, fieldDescriptor, expression.type - ) + IrDeclarationOrigin.DEFINED, + IrFieldSymbolImpl(descriptor), + "topLevelInitializer${topLevelInitializersCounter++}".synthesizedName, + expression.type, + Visibilities.PRIVATE, + isFinal = true, + isExternal = false, + isStatic = true + ).apply { + descriptor.bind(this) - irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression) - - this.addChild(irField) + initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression) + } + addChild(irField) } fun IrClass.addFakeOverrides(symbolTable: SymbolTable) { @@ -155,72 +146,6 @@ fun IrFunction.createParameterDeclarations(symbolTable: SymbolTable) { } } -private fun createFakeOverride( - descriptor: CallableMemberDescriptor, - overriddenDeclarations: List, - irClass: IrClass -): IrDeclaration { - - // TODO: this function doesn't substitute types. - fun IrSimpleFunction.copyFake(descriptor: FunctionDescriptor): IrSimpleFunction = IrFunctionImpl( - irClass.startOffset, irClass.endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor, returnType - ).also { - it.parent = irClass - it.createDispatchReceiverParameter() - - it.extensionReceiverParameter = this.extensionReceiverParameter?.let { - IrValueParameterImpl( - it.startOffset, - it.endOffset, - IrDeclarationOrigin.DEFINED, - it.descriptor.extensionReceiverParameter!!, - it.type, - null - ) - } - - this.valueParameters.mapTo(it.valueParameters) { oldParameter -> - IrValueParameterImpl( - oldParameter.startOffset, - oldParameter.endOffset, - IrDeclarationOrigin.DEFINED, - it.descriptor.valueParameters[oldParameter.index], - oldParameter.type, - (oldParameter as? IrValueParameter)?.varargElementType - ) - } - - this.typeParameters.mapTo(it.typeParameters) { oldParameter -> - IrTypeParameterImpl( - irClass.startOffset, - irClass.endOffset, - IrDeclarationOrigin.DEFINED, - it.descriptor.typeParameters[oldParameter.index] - ).apply { - superTypes += oldParameter.superTypes - } - } - } - - val copiedDeclaration = overriddenDeclarations.first() - - return when (copiedDeclaration) { - is IrSimpleFunction -> copiedDeclaration.copyFake(descriptor as FunctionDescriptor) - is IrProperty -> IrPropertyImpl( - irClass.startOffset, - irClass.endOffset, - IrDeclarationOrigin.FAKE_OVERRIDE, - descriptor as PropertyDescriptor - ).apply { - parent = irClass - getter = copiedDeclaration.getter?.copyFake(descriptor.getter!!) - setter = copiedDeclaration.setter?.copyFake(descriptor.setter!!) - } - else -> error(copiedDeclaration) - } -} - - fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) { assert(this.overriddenSymbols.isEmpty()) @@ -229,44 +154,6 @@ fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) { } } -fun IrClass.simpleFunctions(): List = this.declarations.flatMap { - when (it) { - is IrSimpleFunction -> listOf(it) - is IrProperty -> listOfNotNull(it.getter, it.setter) - else -> emptyList() - } -} - -fun IrClass.createParameterDeclarations() { - thisReceiver = IrValueParameterImpl( - startOffset, endOffset, - IrDeclarationOrigin.INSTANCE_RECEIVER, - descriptor.thisAsReceiverParameter, - this.symbol.typeWith(this.typeParameters.map { it.defaultType }), - null - ).also { valueParameter -> - valueParameter.parent = this - } - - assert(typeParameters.isEmpty()) - assert(descriptor.declaredTypeParameters.isEmpty()) -} - -fun IrFunction.createDispatchReceiverParameter() { - assert(this.dispatchReceiverParameter == null) - - val descriptor = this.descriptor.dispatchReceiverParameter ?: return - - this.dispatchReceiverParameter = IrValueParameterImpl( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - descriptor, - (parent as IrClass).defaultType, - null - ).also { it.parent = this } -} - fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) { this.descriptor.declaredTypeParameters.mapTo(this.typeParameters) { IrTypeParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, it).apply { @@ -283,29 +170,6 @@ fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) { ) } -fun IrClass.setSuperSymbols(superTypes: List) { - val supers = superTypes.map { it.getClass()!! } - assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet()) - assert(this.superTypes.isEmpty()) - this.superTypes += superTypes - - val superMembers = supers.flatMap { - it.simpleFunctions() - }.associateBy { it.descriptor } - - this.simpleFunctions().forEach { - assert(it.overriddenSymbols.isEmpty()) - - it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) { - val superMember = superMembers[it.original] ?: error(it.original) - superMember.symbol - } - } -} - -private fun IrClass.superDescriptors() = - this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor } - fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) { assert(this.superTypes.isEmpty()) this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) } @@ -315,52 +179,110 @@ fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) { } } -fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List) { - val overriddenSuperMembers = this.declarations.map { it.descriptor } - .filterIsInstance().flatMap { it.overriddenDescriptors.map { it.original } }.toSet() +fun IrClass.simpleFunctions() = declarations.flatMap { + when (it) { + is IrSimpleFunction -> listOf(it) + is IrProperty -> listOfNotNull(it.getter, it.setter) + else -> emptyList() + } +} - val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap { - it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull { - when (it) { - is IrSimpleFunction -> it.descriptor to it - is IrProperty -> it.descriptor to it - else -> null +fun IrClass.createParameterDeclarations() { + assert (thisReceiver == null) + + thisReceiver = WrappedReceiverParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + IrDeclarationOrigin.INSTANCE_RECEIVER, + IrValueParameterSymbolImpl(it), + Name.special(""), + 0, + symbol.typeWith(typeParameters.map { it.defaultType }), + null, + false, + false + ).apply { + it.bind(this) + parent = this@createParameterDeclarations + } + } +} + +fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = null) { + assert(dispatchReceiverParameter == null) + + dispatchReceiverParameter = WrappedReceiverParameterDescriptor().let { + IrValueParameterImpl( + startOffset, endOffset, + origin ?: parentAsClass.origin, + IrValueParameterSymbolImpl(it), + Name.special(""), + 0, + parentAsClass.defaultType, + null, + false, + false + ).apply { + it.bind(this) + parent = this@createDispatchReceiverParameter + } + } +} + +fun IrClass.addFakeOverrides() { + fun IrDeclaration.toList() = when (this) { + is IrSimpleFunction -> listOf(this) + is IrProperty -> listOfNotNull(getter, setter) + else -> emptyList() + } + + val overriddenFunctions = declarations + .flatMap { it.toList() } + .flatMap { it.overriddenSymbols.map { it.owner } } + .toSet() + + val unoverriddenSuperFunctions = superTypes + .map { it.getClass()!! } + .flatMap { irClass -> + irClass.declarations + .flatMap { it.toList() } + .filter { it !in overriddenFunctions } } - } - }.toMap() + .toMutableSet() - val irClass = this + // TODO: A dirty hack. + val groupedUnoverriddenSuperFunctions = unoverriddenSuperFunctions.groupBy { it.name.asString() + it.allParameters.size } - val overridingStrategy = object : OverridingStrategy() { - override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) { - val overriddenDeclarations = - fakeOverride.overriddenDescriptors.map { unoverriddenSuperMembers[it]!! } + fun createFakeOverride(overriddenFunctions: List) = + overriddenFunctions.first().let { irFunction -> + val descriptor = WrappedSimpleFunctionDescriptor() + IrFunctionImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + IrDeclarationOrigin.FAKE_OVERRIDE, + IrSimpleFunctionSymbolImpl(descriptor), + irFunction.name, + Visibilities.INHERITED, + Modality.OPEN, + irFunction.returnType, + irFunction.isInline, + irFunction.isExternal, + irFunction.isTailrec, + irFunction.isSuspend + ).apply { + descriptor.bind(this) + parent = this@addFakeOverrides + overriddenSymbols += overriddenFunctions.map { it.symbol } + copyParameterDeclarationsFrom(irFunction) + } + } - assert(overriddenDeclarations.isNotEmpty()) + val fakeOverriddenFunctions = groupedUnoverriddenSuperFunctions + .asSequence() + .associate { it.value.first() to createFakeOverride(it.value) } + .toMutableMap() - irClass.declarations.add(createFakeOverride(fakeOverride, overriddenDeclarations, irClass)) - } - - override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) { - error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second") - } - - override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) { - error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent") - } - } - - unoverriddenSuperMembers.keys.groupBy { it.name }.forEach { (name, members) -> - OverridingUtil.generateOverridesInFunctionGroup( - name, - members, - emptyList(), - this.descriptor, - overridingStrategy - ) - } - - this.setSuperSymbols(superTypes) + declarations += fakeOverriddenFunctions.values } private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int = @@ -389,6 +311,11 @@ fun IrDeclarationContainer.addChild(declaration: IrDeclaration) { declaration.accept(SetDeclarationsParentVisitor, this) } +fun T.setDeclarationsParent(parent: IrDeclarationParent): T { + accept(SetDeclarationsParentVisitor, parent) + return this +} + object SetDeclarationsParentVisitor : IrElementVisitor { override fun visitElement(element: IrElement, data: IrDeclarationParent) { if (element !is IrDeclarationParent) { @@ -612,25 +539,6 @@ fun IrMemberAccessExpression.getArgumentsWithIr(): List, - startOffset: Int, endOffset: Int + arrayElements: List ): IrExpression { val arrayType = ir.symbols.array.typeWith(arrayElementType) @@ -659,34 +567,27 @@ fun CommonBackendContext.createArrayOfExpression( fun createField( startOffset: Int, endOffset: Int, + origin: IrDeclarationOrigin, type: IrType, name: Name, isMutable: Boolean, - origin: IrDeclarationOrigin, - owner: ClassDescriptor -): IrField { - val descriptor = PropertyDescriptorImpl.create( - /* containingDeclaration = */ owner, - /* annotations = */ Annotations.EMPTY, - /* modality = */ Modality.FINAL, - /* visibility = */ Visibilities.PRIVATE, - /* isVar = */ isMutable, - /* name = */ name, - /* kind = */ CallableMemberDescriptor.Kind.DECLARATION, - /* source = */ SourceElement.NO_SOURCE, - /* lateInit = */ false, - /* isConst = */ false, - /* isExpect = */ false, - /* isActual = */ false, - /* isExternal = */ false, - /* isDelegated = */ false + owner: IrClass +) = WrappedFieldDescriptor().let { + IrFieldImpl( + startOffset, endOffset, + origin, + IrFieldSymbolImpl(it), + name, + type, + Visibilities.PRIVATE, + !isMutable, + false, + false ).apply { - initialize(null, null) - - setType(type.toKotlinType(), emptyList(), owner.thisAsReceiverParameter, null) + it.bind(this) + owner.declarations += this + parent = owner } - - return IrFieldImpl(startOffset, endOffset, origin, descriptor, type) } fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { @@ -710,16 +611,5 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType -fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor { - return this.newCopyBuilder() - .setOwner(owner) - .setCopyOverrides(true) - .setModality(if (final) Modality.FINAL else Modality.OPEN) - .setDispatchReceiverParameter(owner.thisAsReceiverParameter) - .build()!!.apply { - overriddenDescriptors = listOf(this@createOverriddenDescriptor) - } -} - fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean = this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true