diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt index 1996d6bea79..e9828181019 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name @@ -42,25 +43,26 @@ class PropertiesLowering( override fun visitClass(declaration: IrClass): IrStatement { declaration.transformChildrenVoid(this) declaration.transformDeclarationsFlat { lowerProperty(it, declaration.kind) } - declaration.declarations.removeAll { it is IrProperty } return declaration } private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List? = if (declaration is IrProperty) - ArrayList(4).apply { - // JvmFields in a companion object refer to companion's owners and should not be generated within companion. - if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) { - addIfNotNull(declaration.backingField) - } - addIfNotNull(declaration.getter) - addIfNotNull(declaration.setter) + if (declaration.isEffectivelyExternal()) listOf(declaration) else { + ArrayList(4).apply { + // JvmFields in a companion object refer to companion's owners and should not be generated within companion. + if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) { + addIfNotNull(declaration.backingField) + } + addIfNotNull(declaration.getter) + addIfNotNull(declaration.setter) - if (declaration.annotations.isNotEmpty() && originOfSyntheticMethodForAnnotations != null - && computeSyntheticMethodName != null - ) { - val methodName = computeSyntheticMethodName.invoke(declaration.name) // Workaround KT-4113 - add(createSyntheticMethodForAnnotations(declaration, originOfSyntheticMethodForAnnotations, methodName)) + if (declaration.annotations.isNotEmpty() && originOfSyntheticMethodForAnnotations != null + && computeSyntheticMethodName != null + ) { + val methodName = computeSyntheticMethodName.invoke(declaration.name) // Workaround KT-4113 + add(createSyntheticMethodForAnnotations(declaration, originOfSyntheticMethodForAnnotations, methodName)) + } } } else diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrBackendUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrBackendUtils.kt index 1dda3056efe..33eb31a94b3 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrBackendUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrBackendUtils.kt @@ -18,20 +18,24 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.name.Name fun IrClassSymbol.getPropertyDeclaration(name: String) = this.owner.declarations.filterIsInstance() .atMostOne { it.descriptor.name == Name.identifier(name) } -fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? = - this.getPropertyDeclaration(name)?.getter?.symbol +fun IrClassSymbol.getSimpleFunction(name: String): IrSimpleFunctionSymbol? = + owner.findDeclaration { it.name.asString() == name }?.symbol -fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? = - this.getPropertyDeclaration(name)?.setter?.symbol +fun IrClassSymbol.getPropertyGetter(name: String): IrSimpleFunctionSymbol? = + this.getPropertyDeclaration(name)?.getter?.symbol ?: this.getSimpleFunction("") + +fun IrClassSymbol.getPropertySetter(name: String): IrSimpleFunctionSymbol? = + this.getPropertyDeclaration(name)?.setter?.symbol ?: this.getSimpleFunction("") fun IrClassSymbol.getPropertyField(name: String): IrFieldSymbol? = this.getPropertyDeclaration(name)?.backingField?.symbol diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index fd656edc6a4..12bb25b715f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -31,9 +31,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl -import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.ir.util.getPropertyDeclaration -import org.jetbrains.kotlin.ir.util.kotlinPackageFqn +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -257,10 +255,14 @@ class JsIrBackendContext( val throwNWBESymbol = ir.symbols.ThrowNoWhenBranchMatchedException val throwUPAESymbol = ir.symbols.ThrowUninitializedPropertyAccessException - val coroutineImplLabelProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("state")!! } - val coroutineImplResultSymbol by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("result")!! } - val coroutineImplExceptionProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("exception")!! } - val coroutineImplExceptionStateProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("exceptionState")!! } + val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner } + val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner } + val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner } + val coroutineImplResultSymbolSetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner } + val coroutineImplExceptionPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner } + val coroutineImplExceptionPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner } + val coroutineImplExceptionStatePropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exceptionState")!!.owner } + val coroutineImplExceptionStatePropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exceptionState")!!.owner } val primitiveClassProperties by lazy { primitiveClassesObject.owner.declarations.filterIsInstance() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 17456d85bbb..ba01386a685 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -81,18 +81,6 @@ private val expectDeclarationsRemovingPhase = makeJsModulePhase( description = "Remove expect declaration from module fragment" ) -private val coroutineIntrinsicLoweringPhase = makeJsModulePhase( - ::CoroutineIntrinsicLowering, - name = "CoroutineIntrinsicLowering", - description = "Replace common coroutine intrinsics with platform specific ones" -) - -private val arrayInlineConstructorLoweringPhase = makeJsModulePhase( - ::ArrayInlineConstructorLowering, - name = "ArrayInlineConstructorLowering", - description = "Replace array constructor with platform specific factory functions" -) - private val lateinitLoweringPhase = makeJsModulePhase( ::LateinitLowering, name = "LateinitLowering", @@ -107,7 +95,7 @@ private val functionInliningPhase = makeCustomJsModulePhase( }, name = "FunctionInliningPhase", description = "Perform function inlining", - prerequisite = setOf(lateinitLoweringPhase, arrayInlineConstructorLoweringPhase, coroutineIntrinsicLoweringPhase) + prerequisite = setOf(expectDeclarationsRemovingPhase) ) private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase( @@ -136,16 +124,24 @@ private val unitMaterializationLoweringPhase = makeJsModulePhase( prerequisite = setOf(tailrecLoweringPhase) ) +private val enumClassConstructorLoweringPhase = makeJsModulePhase( + ::EnumClassConstructorLowering, + name = "EnumClassConstructorLowering", + description = "Transform Enum Class into regular Class" +) + private val enumClassLoweringPhase = makeJsModulePhase( ::EnumClassLowering, name = "EnumClassLowering", - description = "Transform Enum Class into regular Class" + description = "Transform Enum Class into regular Class", + prerequisite = setOf(enumClassConstructorLoweringPhase) ) private val enumUsageLoweringPhase = makeJsModulePhase( ::EnumUsageLowering, name = "EnumUsageLowering", - description = "Replace enum access with invocation of corresponding function" + description = "Replace enum access with invocation of corresponding function", + prerequisite = setOf(enumClassLoweringPhase) ) private val sharedVariablesLoweringPhase = makeJsModulePhase( @@ -171,7 +167,7 @@ private val localDeclarationsLoweringPhase = makeJsModulePhase( ::LocalDeclarationsLowering, name = "LocalDeclarationsLowering", description = "Move local declarations into nearest declaration container", - prerequisite = setOf(sharedVariablesLoweringPhase) + prerequisite = setOf(sharedVariablesLoweringPhase, localDelegatedPropertiesLoweringPhase) ) private val innerClassesLoweringPhase = makeJsModulePhase( @@ -190,7 +186,7 @@ private val suspendFunctionsLoweringPhase = makeJsModulePhase( ::SuspendFunctionsLowering, name = "SuspendFunctionsLowering", description = "Transform suspend functions into CoroutineImpl instance and build state machine", - prerequisite = setOf(unitMaterializationLoweringPhase, coroutineIntrinsicLoweringPhase) + prerequisite = setOf(unitMaterializationLoweringPhase) ) private val privateMembersLoweringPhase = makeJsModulePhase( @@ -253,7 +249,7 @@ private val initializersLoweringPhase = makeCustomJsModulePhase( { context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) }, name = "InitializersLowering", description = "Merge init block and field initializers into [primary] constructor", - prerequisite = setOf(enumClassLoweringPhase) + prerequisite = setOf(enumClassConstructorLoweringPhase) ) private val multipleCatchesLoweringPhase = makeJsModulePhase( @@ -344,24 +340,24 @@ private val callsLoweringPhase = makeJsModulePhase( val jsPhases = namedIrModulePhase( name = "IrModuleLowering", description = "IR module lowering", - lower = moveBodilessDeclarationsToSeparatePlacePhase then - expectDeclarationsRemovingPhase then - coroutineIntrinsicLoweringPhase then - arrayInlineConstructorLoweringPhase then - lateinitLoweringPhase then + lower = expectDeclarationsRemovingPhase then functionInliningPhase then - removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then - throwableSuccessorsLoweringPhase then + lateinitLoweringPhase then tailrecLoweringPhase then - unitMaterializationLoweringPhase then - enumClassLoweringPhase then - enumUsageLoweringPhase then + enumClassConstructorLoweringPhase then sharedVariablesLoweringPhase then - returnableBlockLoweringPhase then localDelegatedPropertiesLoweringPhase then localDeclarationsLoweringPhase then innerClassesLoweringPhase then innerClassConstructorCallsLoweringPhase then + propertiesLoweringPhase then + initializersLoweringPhase then + // Common prefix ends + moveBodilessDeclarationsToSeparatePlacePhase then + enumClassLoweringPhase then + enumUsageLoweringPhase then + returnableBlockLoweringPhase then + unitMaterializationLoweringPhase then suspendFunctionsLoweringPhase then privateMembersLoweringPhase then callableReferenceLoweringPhase then @@ -369,9 +365,9 @@ val jsPhases = namedIrModulePhase( defaultParameterInjectorPhase then defaultParameterCleanerPhase then jsDefaultCallbackGeneratorPhase then + removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then + throwableSuccessorsLoweringPhase then varargLoweringPhase then - propertiesLoweringPhase then - initializersLoweringPhase then multipleCatchesLoweringPhase then bridgesConstructionPhase then typeOperatorLoweringPhase then diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ArrayInlineConstructorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ArrayInlineConstructorLowering.kt index 043b4488576..bb525898c92 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ArrayInlineConstructorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ArrayInlineConstructorLowering.kt @@ -5,40 +5,25 @@ package org.jetbrains.kotlin.ir.backend.js.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.util.irCall -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid // Replace array inline constructors with stdlib function invocations -// Should be performed before inliner -class ArrayInlineConstructorLowering(val context: JsIrBackendContext) : FileLoweringPass { - override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid(ArrayConstructorTransformer(context)) - } -} - -private class ArrayConstructorTransformer( +class ArrayConstructorTransformer( val context: JsIrBackendContext -) : IrElementTransformerVoid() { - +) { // Inline constructor for CharArray is implemented in runtime private val primitiveArrayInlineToSizeConstructorMap = context.intrinsics.primitiveArrays.filter { it.value != PrimitiveType.CHAR }.keys.associate { it.inlineConstructor to it.sizeConstructor } - override fun visitCall(expression: IrCall): IrExpression { - expression.transformChildrenVoid(this) - + fun transformCall(expression: IrCall): IrCall { if (expression.symbol == context.intrinsics.array.inlineConstructor) { return irCall(expression, context.intrinsics.jsArray) } else { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 55a65610e2a..0b61eaaade2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -85,15 +85,11 @@ class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass { class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass { override fun lower(irDeclarationContainer: IrDeclarationContainer) { irDeclarationContainer.transformDeclarationsFlat { declaration -> - if (declaration is IrClass && declaration.isEnumClass) { - if (declaration.descriptor.isExpect) { - emptyList() - } else { - EnumClassTransformer(context, declaration).transform() - } - } else { - listOf(declaration) - } + if (declaration is IrClass && declaration.isEnumClass && + !declaration.descriptor.isExpect && !declaration.isEffectivelyExternal() + ) { + EnumClassTransformer(context, declaration).transform() + } else null } } } @@ -104,12 +100,22 @@ private fun createEntryAccessorName(enumName: String, enumEntry: IrEnumEntry) = private fun IrEnumEntry.getType(irClass: IrClass) = (correspondingClass ?: irClass).defaultType -class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) { +class EnumClassConstructorLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass { + override fun lower(irDeclarationContainer: IrDeclarationContainer) { + irDeclarationContainer.transformDeclarationsFlat { declaration -> + if (declaration is IrClass && declaration.isEnumClass && + !declaration.descriptor.isExpect && !declaration.isEffectivelyExternal() + ) { + EnumClassConstructorTransformer(context, declaration).transform() + } else null + } + } +} + +class EnumClassConstructorTransformer(val context: JsIrBackendContext, private val irClass: IrClass) { private val builder = context.createIrBuilder(irClass.symbol) private val enumEntries = irClass.declarations.filterIsInstance() private val loweredEnumConstructors = HashMap() - private val enumName = irClass.name.identifier - private val throwISESymbol = context.throwISEymbol fun transform(): List { // Make sure InstanceInitializer exists @@ -124,35 +130,16 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: // The first step creates a new `IrConstructor` with new `IrValueParameter`s so references to old `IrValueParameter`s must be replaced with new ones. fixReferencesToConstructorParameters() - // Create instance variable for each enum entry initialized with `null` - val entryInstances = createEnumEntryInstanceVariables() - // Lower `IrEnumConstructorCall`s inside of enum entry class constructors to corresponding `IrDelegatingConstructorCall`s. // Add `name` and `ordinal` parameters. - lowerEnumEntryClassConstructors(entryInstances) + lowerEnumEntryClassConstructors() // Lower `IrEnumConstructorCall`s to corresponding `IrCall`s. // Add `name` and `ordinal` constant parameters only for calls to the "enum class" constructors ("enum entry class" constructors // already delegate these parameters) lowerEnumEntryInitializerExpression() - // Create boolean flag that indicates if entry instances were initialized. - val entryInstancesInitializedVar = createEntryInstancesInitializedVar() - - // Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`. - // It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing. - val initEntryInstancesFun = createInitEntryInstancesFun(entryInstancesInitializedVar, entryInstances) - - // Create entry instance getters. These are used to lower `IrGetEnumValue`. - val entryGetInstanceFuns = createGetEntryInstanceFuns(initEntryInstancesFun, entryInstances) - - // Create body for `values` and `valueOf` functions - lowerSyntheticFunctions() - - // Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them). - replaceIrEntriesWithCorrespondingClasses() - - return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns + return listOf(irClass) } private fun insertInstanceInitializer() { @@ -182,6 +169,82 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: }) } + private fun lowerEnumConstructorsSignature() { + irClass.declarations.transform { declaration -> + if (declaration is IrConstructor) { + transformEnumConstructor(declaration, irClass) + } else + declaration + } + } + + private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor { + val loweredConstructorDescriptor = WrappedClassConstructorDescriptor() + val loweredConstructorSymbol = IrConstructorSymbolImpl(loweredConstructorDescriptor) + + return IrConstructorImpl( + enumConstructor.startOffset, + enumConstructor.endOffset, + enumConstructor.origin, + loweredConstructorSymbol, + enumConstructor.name, + enumConstructor.visibility, + enumConstructor.returnType, + enumConstructor.isInline, + enumConstructor.isExternal, + enumConstructor.isPrimary + ).apply { + loweredConstructorDescriptor.bind(this) + parent = enumClass + valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this } + valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this } + copyParameterDeclarationsFrom(enumConstructor) + body = enumConstructor.body + loweredEnumConstructors[enumConstructor.symbol] = this + + this.acceptVoid(PatchDeclarationParentsVisitor(enumClass)) + } + } + + private fun lowerEnumConstructorsBody() { + irClass.declarations.filterIsInstance().forEach { + IrEnumClassConstructorTransformer(it).transformBody() + } + } + + private inner class IrEnumClassConstructorTransformer(val constructor: IrConstructor) : IrElementTransformerVoid() { + val builder = context.createIrBuilder(constructor.symbol) + + fun transformBody() { + constructor.body?.transformChildrenVoid(this) + } + + override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) = + builder.irDelegatingConstructorCall(expression.symbol.owner).apply { + for (i in 0..1) { + putValueArgument(i, builder.irGet(constructor.valueParameters[i])) + } + } + + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { + var delegatingConstructor = expression.symbol.owner + val constructorWasTransformed = delegatingConstructor.symbol in loweredEnumConstructors + + if (constructorWasTransformed) + delegatingConstructor = loweredEnumConstructors[delegatingConstructor.symbol]!! + + return builder.irDelegatingConstructorCall(delegatingConstructor).apply { + var valueArgIdx = 0 + for (i in 0..1) { + putValueArgument(valueArgIdx++, builder.irGet(constructor.valueParameters[i])) + } + for (i in 0 until expression.valueArgumentsCount) { + putValueArgument(valueArgIdx++, expression.getValueArgument(i)) + } + } + } + } + private fun fixReferencesToConstructorParameters() { val fromOldToNewParameter = mutableMapOf() @@ -205,6 +268,92 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: }) } + + private fun lowerEnumEntryClassConstructors() { + for (entry in enumEntries) { + entry.correspondingClass?.constructors?.forEach { + it.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(entry, true)) + } + } + } + + private inner class IrEnumEntryClassConstructorTransformer(val entry: IrEnumEntry, val isInsideConstructor: Boolean) : + IrElementTransformerVoid() { + + private fun buildConstructorCall(constructor: IrConstructor) = + if (isInsideConstructor) + builder.irDelegatingConstructorCall(constructor) + else + builder.irCall(constructor) + + override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression { + var constructor = expression.symbol.owner + val constructorWasTransformed = constructor.symbol in loweredEnumConstructors + + // Enum entry class constructors are not transformed + if (constructorWasTransformed) + constructor = loweredEnumConstructors[constructor.symbol]!! + + return buildConstructorCall(constructor).apply { + var valueArgIdx = 0 + + // Enum entry class constructors already delegate name and ordinal parameters in their body + if (constructorWasTransformed) { + putValueArgument(valueArgIdx++, entry.getNameExpression()) + putValueArgument(valueArgIdx++, entry.getOrdinalExpression()) + } + for (i in 0 until expression.valueArgumentsCount) { + putValueArgument(valueArgIdx++, expression.getValueArgument(i)) + } + } + } + } + + private fun lowerEnumEntryInitializerExpression() { + for (entry in enumEntries) { + entry.initializerExpression = + entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(entry, false), null) + } + } + + private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier) + private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this)) +} + +//------------------------------------------------------- + + +class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) { + private val builder = context.createIrBuilder(irClass.symbol) + private val enumEntries = irClass.declarations.filterIsInstance() + private val enumName = irClass.name.identifier + private val throwISESymbol = context.throwISEymbol + + fun transform(): List { + + // Create instance variable for each enum entry initialized with `null` + val entryInstances = createEnumEntryInstanceVariables() + + // Create boolean flag that indicates if entry instances were initialized. + val entryInstancesInitializedVar = createEntryInstancesInitializedVar() + + // Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`. + // It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing. + val initEntryInstancesFun = createInitEntryInstancesFun(entryInstancesInitializedVar, entryInstances) + + // Create entry instance getters. These are used to lower `IrGetEnumValue`. + val entryGetInstanceFuns = createGetEntryInstanceFuns(initEntryInstancesFun, entryInstances) + + // Create body for `values` and `valueOf` functions + lowerSyntheticFunctions() + + // Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them). + replaceIrEntriesWithCorrespondingClasses() + + return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns + } + + private fun createEnumValueOfBody(): IrBody { val valueOfFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUEOF) val nameParameter = valueOfFun.valueParameters[0] @@ -249,25 +398,9 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } - private fun lowerEnumConstructorsSignature() { - irClass.declarations.transform { declaration -> - if (declaration is IrConstructor) { - transformEnumConstructor(declaration, irClass) - } else - declaration - } - } - - private fun lowerEnumConstructorsBody() { - irClass.declarations.filterIsInstance().forEach { - IrEnumClassConstructorTransformer(it).transformBody() - } - } - private fun lowerEnumEntryClassConstructors(entryInstances: List) { for ((entry, instance) in enumEntries.zip(entryInstances)) { entry.correspondingClass?.constructors?.forEach { - it.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(entry, true)) // Initialize entry instance at the beginning of constructor so it can be used inside constructor body (it.body as? IrBlockBody)?.apply { @@ -279,19 +412,23 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } } - private fun lowerEnumEntryInitializerExpression() { - for (entry in enumEntries) { - entry.initializerExpression = - entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(entry, false), null) - } - } - private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry -> val type = enumEntry.getType(irClass).makeNullable(false) val name = "${enumName}_${enumEntry.name.identifier}_instance" - builder.run { + val result = builder.run { scope.createTmpVariable(irImplicitCast(irNull(), type), name) } + + enumEntry.correspondingClass?.constructors?.forEach { + // Initialize entry instance at the beginning of constructor so it can be used inside constructor body + (it.body as? IrBlockBody)?.apply { + statements.add(0, context.createIrBuilder(it.symbol).run { + irSetVar(result.symbol, irGet(enumEntry.correspondingClass!!.thisReceiver!!)) + }) + } + } + + result } private fun replaceIrEntriesWithCorrespondingClasses() { @@ -346,98 +483,6 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: ) } - private inner class IrEnumClassConstructorTransformer(val constructor: IrConstructor) : IrElementTransformerVoid() { - val builder = context.createIrBuilder(constructor.symbol) - - fun transformBody() { - constructor.body?.transformChildrenVoid(this) - } - - override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) = - builder.irDelegatingConstructorCall(expression.symbol.owner).apply { - for (i in 0..1) { - putValueArgument(i, builder.irGet(constructor.valueParameters[i])) - } - } - - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { - var delegatingConstructor = expression.symbol.owner - val constructorWasTransformed = delegatingConstructor.symbol in loweredEnumConstructors - - if (constructorWasTransformed) - delegatingConstructor = loweredEnumConstructors[delegatingConstructor.symbol]!! - - return builder.irDelegatingConstructorCall(delegatingConstructor).apply { - var valueArgIdx = 0 - for (i in 0..1) { - putValueArgument(valueArgIdx++, builder.irGet(constructor.valueParameters[i])) - } - for (i in 0 until expression.valueArgumentsCount) { - putValueArgument(valueArgIdx++, expression.getValueArgument(i)) - } - } - } - } - - private inner class IrEnumEntryClassConstructorTransformer(val entry: IrEnumEntry, val isInsideConstructor: Boolean) : - IrElementTransformerVoid() { - - private fun buildConstructorCall(constructor: IrConstructor) = - if (isInsideConstructor) - builder.irDelegatingConstructorCall(constructor) - else - builder.irCall(constructor) - - override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression { - var constructor = expression.symbol.owner - val constructorWasTransformed = constructor.symbol in loweredEnumConstructors - - // Enum entry class constructors are not transformed - if (constructorWasTransformed) - constructor = loweredEnumConstructors[constructor.symbol]!! - - return buildConstructorCall(constructor).apply { - var valueArgIdx = 0 - - // Enum entry class constructors already delegate name and ordinal parameters in their body - if (constructorWasTransformed) { - putValueArgument(valueArgIdx++, entry.getNameExpression()) - putValueArgument(valueArgIdx++, entry.getOrdinalExpression()) - } - for (i in 0 until expression.valueArgumentsCount) { - putValueArgument(valueArgIdx++, expression.getValueArgument(i)) - } - } - } - } - - private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor { - val loweredConstructorDescriptor = WrappedClassConstructorDescriptor() - val loweredConstructorSymbol = IrConstructorSymbolImpl(loweredConstructorDescriptor) - - return IrConstructorImpl( - enumConstructor.startOffset, - enumConstructor.endOffset, - enumConstructor.origin, - loweredConstructorSymbol, - enumConstructor.name, - enumConstructor.visibility, - enumConstructor.returnType, - enumConstructor.isInline, - enumConstructor.isExternal, - enumConstructor.isPrimary - ).apply { - loweredConstructorDescriptor.bind(this) - parent = enumClass - valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this } - valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this } - copyParameterDeclarationsFrom(enumConstructor) - body = enumConstructor.body - loweredEnumConstructors[enumConstructor.symbol] = this - - this.acceptVoid(PatchDeclarationParentsVisitor(enumClass)) - } - } private fun findFunctionDescriptorForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction = irClass.declarations.asSequence().filterIsInstance() @@ -459,7 +504,4 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: ) = JsIrBuilder.buildFunction(name, returnType, irClass).also { it.body = context.createIrBuilder(it.symbol).irBlockBody(it, bodyBuilder) } - - private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier) - private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this)) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ThrowableSuccessorsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ThrowableSuccessorsLowering.kt index 6c88efa9330..6ca153e8d63 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ThrowableSuccessorsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ThrowableSuccessorsLowering.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.isThrowable import org.jetbrains.kotlin.ir.util.isThrowableTypeOrSubtype +import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name @@ -147,12 +148,25 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin if (isDirectChildOfThrowable(declaration)) { val messageField = createBackingField(declaration, messagePropertyName, stringType) val causeField = createBackingField(declaration, causePropertyName, throwableType) + val existedMessageAccessor = ownPropertyAccessor(declaration, messageGetter) - if (existedMessageAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) + val newMessageAccessor = if (existedMessageAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) { createPropertyAccessor(existedMessageAccessor, messageField) + } else existedMessageAccessor + val existedCauseAccessor = ownPropertyAccessor(declaration, causeGetter) - if (existedCauseAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) + val newCauseAccessor = if (existedCauseAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) { createPropertyAccessor(existedCauseAccessor, causeField) + } else existedCauseAccessor + + + declaration.declarations.transformFlat { + when (it) { + existedMessageAccessor -> listOf(newMessageAccessor) + existedCauseAccessor -> listOf(newCauseAccessor) + else -> null + } + } pendingSuperUsages += DirectThrowableSuccessors(declaration, messageField, causeField) } @@ -181,7 +195,7 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin return fieldDeclaration } - private fun createPropertyAccessor(fakeAccessor: IrSimpleFunction, field: IrField) { + private fun createPropertyAccessor(fakeAccessor: IrSimpleFunction, field: IrField): IrSimpleFunction { val name = fakeAccessor.name val function = JsIrBuilder.buildFunction(name, fakeAccessor.returnType, fakeAccessor.parent).apply { overriddenSymbols += fakeAccessor.overriddenSymbols @@ -194,7 +208,7 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin val returnStatement = JsIrBuilder.buildReturn(function.symbol, returnValue, nothingType) function.body = JsIrBuilder.buildBlockBody(listOf(returnStatement)) - fakeAccessor.correspondingProperty?.getter = function + return function } } @@ -315,7 +329,8 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin private fun isDirectChildOfThrowable(irClass: IrClass) = irClass.superTypes.any { it.isThrowable() } private fun ownPropertyAccessor(irClass: IrClass, irBase: IrFunctionSymbol) = irClass.declarations.filterIsInstance().mapNotNull { it.getter } - .single { it.overriddenSymbols.any { s -> s == irBase } } + .singleOrNull { it.overriddenSymbols.any { s -> s == irBase } } + ?: irClass.declarations.filterIsInstance().single { it.overriddenSymbols.any { s -> s == irBase } } inner class ThrowablePropertiesUsageTransformer : IrElementTransformerVoid() { override fun visitCall(expression: IrCall): IrExpression { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index dfe4ef27394..37ef4d1b890 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -244,7 +244,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass { } val typeParameter = typeParameterSymbol.owner - assert(!typeParameter.isReified) { "reified parameters have to be lowered before" } + // TODO either remove functions with reified type parameters or support this case + // assert(!typeParameter.isReified) { "reified parameters have to be lowered before" } return typeParameter.superTypes.fold(litTrue) { r, t -> val check = generateTypeCheckNonNull(argument.copy(), t.makeNotNull(false)) calculator.and(r, check) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/PrimitiveContainerMemberCallTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/PrimitiveContainerMemberCallTransformer.kt index bdf76a5cea2..4dc70fbbfb0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/PrimitiveContainerMemberCallTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/PrimitiveContainerMemberCallTransformer.kt @@ -7,12 +7,12 @@ package org.jetbrains.kotlin.ir.backend.js.lower.calls import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.util.getSimpleFunction +import org.jetbrains.kotlin.ir.util.getPropertyGetter class PrimitiveContainerMemberCallTransformer(private val context: JsIrBackendContext) : CallsTransformer { private val intrinsics = context.intrinsics @@ -65,22 +65,22 @@ class PrimitiveContainerMemberCallTransformer(private val context: JsIrBackendCo } private val IrClassSymbol.sizeProperty - get() = owner.declarations.filterIsInstance().first { it.name.asString() == "size" }.getter!!.symbol + get() = getPropertyGetter("size")!! private val IrClassSymbol.getFunction - get() = owner.declarations.filterIsInstance().first { it.name.asString() == "get" }.symbol + get() = getSimpleFunction("get")!! private val IrClassSymbol.setFunction - get() = owner.declarations.filterIsInstance().first { it.name.asString() == "set" }.symbol + get() = getSimpleFunction("set")!! private val IrClassSymbol.iterator - get() = owner.declarations.filterIsInstance().first { it.name.asString() == "iterator" }.symbol + get() = getSimpleFunction("iterator")!! private val IrClassSymbol.sizeConstructor get() = owner.declarations.filterIsInstance().first { it.valueParameters.size == 1 }.symbol private val IrClassSymbol.lengthProperty - get() = owner.declarations.filterIsInstance().first { it.name.asString() == "length" }.getter!!.symbol + get() = getPropertyGetter("length")!! private val IrClassSymbol.subSequence - get() = owner.declarations.filterIsInstance().single { it.name.asString() == "subSequence" }.symbol + get() = getSimpleFunction("subSequence")!! diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt index 2339423372e..8aca50c3c6f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* @@ -64,9 +65,11 @@ class StateMachineBuilder( val context: JsIrBackendContext, val function: IrFunctionSymbol, private val rootLoop: IrLoop, - private val exceptionSymbol: IrProperty, - private val exStateSymbol: IrProperty, - private val stateSymbol: IrProperty, + private val exceptionSymbolGetter: IrSimpleFunction, + private val exceptionSymbolSetter: IrSimpleFunction, + private val exStateSymbolGetter: IrSimpleFunction, + private val exStateSymbolSetter: IrSimpleFunction, + private val stateSymbolSetter: IrSimpleFunction, private val thisSymbol: IrValueParameterSymbol, private val suspendResult: IrVariableSymbol ) : IrElementVisitorVoid { @@ -84,7 +87,7 @@ class StateMachineBuilder( val entryState = SuspendState(unit) val rootExceptionTrap = buildExceptionTrapState() - private val globalExceptionVar = JsIrBuilder.buildVar(exceptionSymbol.getter!!.returnType, function.owner, "e") + private val globalExceptionVar = JsIrBuilder.buildVar(exceptionSymbolGetter.returnType, function.owner, "e") lateinit var globalCatch: IrCatch fun finalizeStateMachine() { @@ -118,11 +121,11 @@ class StateMachineBuilder( ) // TODO: exception table - elseBlock.statements += JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply { + elseBlock.statements += JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply { dispatchReceiver = thisReceiver putValueArgument(0, exceptionState()) } - elseBlock.statements += JsIrBuilder.buildCall(exceptionSymbol.setter!!.symbol, unit).apply { + elseBlock.statements += JsIrBuilder.buildCall(exceptionSymbolSetter.symbol, unit).apply { dispatchReceiver = thisReceiver putValueArgument(0, JsIrBuilder.buildGetValue(globalExceptionSymbol)) } @@ -180,7 +183,7 @@ class StateMachineBuilder( private fun doDispatchImpl(target: SuspendState, block: IrContainerExpression, andContinue: Boolean) { val irDispatch = IrDispatchPoint(target) currentState.successors.add(target) - block.addStatement(JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply { + block.addStatement(JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply { dispatchReceiver = thisReceiver putValueArgument(0, irDispatch) }) @@ -297,7 +300,7 @@ class StateMachineBuilder( currentState.successors += continueState transformLastExpression { - JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply { + JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply { dispatchReceiver = thisReceiver putValueArgument(0, dispatch) } @@ -686,7 +689,7 @@ class StateMachineBuilder( aTry.finallyExpression?.acceptVoid(this) currentState.successors += listOf(throwExitState, exitState) addStatement( - JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).also { + JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).also { it.dispatchReceiver = thisReceiver it.putValueArgument(0, JsIrBuilder.buildGetValue(finallyStateVar.symbol)) } @@ -706,15 +709,15 @@ class StateMachineBuilder( private fun setupExceptionState(target: SuspendState) { addStatement( - JsIrBuilder.buildCall(exStateSymbol.setter!!.symbol, unit).apply { + JsIrBuilder.buildCall(exStateSymbolSetter.symbol, unit).apply { dispatchReceiver = thisReceiver putValueArgument(0, IrDispatchPoint(target)) } ) } - private fun exceptionState() = JsIrBuilder.buildCall(exStateSymbol.getter!!.symbol).also { it.dispatchReceiver = thisReceiver } - private fun pendingException() = JsIrBuilder.buildCall(exceptionSymbol.getter!!.symbol).also { it.dispatchReceiver = thisReceiver } + private fun exceptionState() = JsIrBuilder.buildCall(exStateSymbolGetter.symbol).also { it.dispatchReceiver = thisReceiver } + private fun pendingException() = JsIrBuilder.buildCall(exceptionSymbolGetter.symbol).also { it.dispatchReceiver = thisReceiver } private fun buildTryState(aTry: IrTry) = TryState( diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/SuspendFunctionsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/SuspendFunctionsLowering.kt index 988189abf36..c6bee6182e9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/SuspendFunctionsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/SuspendFunctionsLowering.kt @@ -228,8 +228,8 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo builtCoroutines[irFunction] = coroutine if (functionReference == null) { - val resultSetter = context.coroutineImplResultSymbol.setter!! - val exceptionSetter = context.coroutineImplExceptionProperty.setter!! + val resultSetter = context.coroutineImplResultSymbolSetter + val exceptionSetter = context.coroutineImplExceptionPropertySetter // It is not a lambda - replace original function with a call to constructor of the built coroutine. val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset) irFunction.body = irBuilder.irBlockBody(irFunction) { @@ -290,10 +290,13 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo private val create1CompletionParameter = create1Function.valueParameters[0] - private val coroutineImplLabelProperty = context.coroutineImplLabelProperty - private val coroutineImplResultSymbol = context.coroutineImplResultSymbol - private val coroutineImplExceptionProperty = context.coroutineImplExceptionProperty - private val coroutineImplExceptionStateProperty = context.coroutineImplExceptionStateProperty + private val coroutineImplLabelPropertyGetter = context.coroutineImplLabelPropertyGetter + private val coroutineImplLabelPropertySetter = context.coroutineImplLabelPropertySetter + private val coroutineImplResultSymbolGetter = context.coroutineImplResultSymbolGetter + private val coroutineImplExceptionPropertyGetter = context.coroutineImplExceptionPropertyGetter + private val coroutineImplExceptionPropertySetter = context.coroutineImplExceptionPropertySetter + private val coroutineImplExceptionStatePropertyGetter = context.coroutineImplExceptionStatePropertyGetter + private val coroutineImplExceptionStatePropertySetter = context.coroutineImplExceptionStatePropertySetter private val coroutineConstructors = mutableListOf() private var exceptionTrapId = -1 @@ -727,8 +730,8 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo JsIrBuilder.buildValueParameter(p.name, p.index, p.type, p.origin).also { it.parent = declaration } } - val resultSetter = context.coroutineImplResultSymbol.setter!! - val exceptionSetter = context.coroutineImplExceptionProperty.setter!! + val resultSetter = context.coroutineImplResultSymbolSetter + val exceptionSetter = context.coroutineImplExceptionPropertySetter val thisReceiver = declaration.dispatchReceiverParameter!! val irBuilder = context.createIrBuilder(symbol, irFunction.startOffset, irFunction.endOffset) @@ -821,10 +824,10 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo function, "suspendResult", true, - initializer = JsIrBuilder.buildCall(coroutineImplResultSymbol.getter!!.symbol).apply { dispatchReceiver = thisReceiver } + initializer = JsIrBuilder.buildCall(coroutineImplResultSymbolGetter.symbol).apply { dispatchReceiver = thisReceiver } ) - suspendState = JsIrBuilder.buildVar(coroutineImplLabelProperty.getter!!.returnType, function, "suspendState", true) + suspendState = JsIrBuilder.buildVar(coroutineImplLabelPropertyGetter.returnType, function, "suspendState", true) val body = (originalBody as IrBlockBody).run { @@ -848,7 +851,7 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo (it.body as? IrBlockBody)?.run { val receiver = JsIrBuilder.buildGetValue(coroutineClassThis.symbol) val id = JsIrBuilder.buildInt(context.irBuiltIns.intType, exceptionTrapId) - statements += JsIrBuilder.buildCall(coroutineImplExceptionStateProperty.setter!!.symbol).also { call -> + statements += JsIrBuilder.buildCall(coroutineImplExceptionStatePropertySetter.symbol).also { call -> call.dispatchReceiver = receiver call.putValueArgument(0, id) } @@ -880,9 +883,11 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo context, function.symbol, rootLoop, - coroutineImplExceptionProperty, - coroutineImplExceptionStateProperty, - coroutineImplLabelProperty, + coroutineImplExceptionPropertyGetter, + coroutineImplExceptionPropertySetter, + coroutineImplExceptionStatePropertyGetter, + coroutineImplExceptionStatePropertySetter, + coroutineImplLabelPropertySetter, thisReceiver, suspendResult.symbol ) @@ -907,7 +912,7 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo for (state in sortedStates) { val condition = JsIrBuilder.buildCall(eqeqeqInt).apply { - putValueArgument(0, JsIrBuilder.buildCall(coroutineImplLabelProperty.getter!!.symbol).also { + putValueArgument(0, JsIrBuilder.buildCall(coroutineImplLabelPropertyGetter.symbol).also { it.dispatchReceiver = JsIrBuilder.buildGetValue(thisReceiver) }) putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, state.id)) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt index d20b4ea51a0..b6d151c0d10 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt @@ -7,8 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower.inline -import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext -import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.config.languageVersionSettings @@ -19,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irReturn @@ -31,11 +31,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns -import org.jetbrains.kotlin.ir.types.toKotlinType -import org.jetbrains.kotlin.ir.util.file -import org.jetbrains.kotlin.ir.util.getArguments -import org.jetbrains.kotlin.ir.util.parentAsClass -import org.jetbrains.kotlin.ir.util.resolveFakeOverride +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.FqName @@ -53,11 +49,27 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW return irModule.accept(this, data = null) } + private val arrayConstructorTransformer = ArrayConstructorTransformer(context) + override fun visitCall(expression: IrCall): IrExpression { - val callSite = super.visitCall(expression) as IrCall + val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall) val functionDescriptor = callSite.descriptor - if (!functionDescriptor.needsInlining) - return callSite // This call does not need inlining. + + if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining. + + val languageVersionSettings = context.configuration.languageVersionSettings + when { + callSite.symbol == context.ir.symbols.lateinitIsInitializedPropertyGetter -> + return callSite + // Handle coroutine intrinsics + // TODO These should actually be inlined. + callSite.descriptor.isBuiltInIntercepted(languageVersionSettings) -> + error("Continuation.intercepted is not available with release coroutines") + callSite.symbol.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) -> + return irCall(callSite, context.coroutineSuspendOrReturn) + callSite.symbol == context.intrinsics.jsCoroutineContext -> + return irCall(callSite, context.coroutineGetContextJs) + } val callee = getFunctionDeclaration(callSite.symbol) // Get declaration of the function to be inlined. callee.transformChildrenVoid(this) // Process recursive inline. diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt index ff5c36562fa..3ceaa7fde93 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt @@ -21,7 +21,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer