diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt index 814a63e1904..fd417f73394 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt @@ -392,7 +392,7 @@ abstract class AbstractSuspendFunctionsLowering(val co coroutineClass.defaultType, isInline = false, isExternal = false, - isPrimary = false + isPrimary = true ).apply { d.bind(this) parent = coroutineClass 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 40002bc258b..c3aaba0be5f 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 @@ -275,9 +275,7 @@ class JsIrBackendContext( } val throwableConstructors by lazy { throwableClass.owner.declarations.filterIsInstance().map { it.symbol } } - val defaultThrowableCtor by lazy { throwableConstructors.single { it.owner.valueParameters.size == 0 } } - - + val defaultThrowableCtor by lazy { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } } private fun referenceOperators(): Map> { val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol } 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 d71c241faf1..a92ca8cf648 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 @@ -260,11 +260,18 @@ private val propertiesLoweringPhase = makeJsModulePhase( description = "Move fields and accessors out from its property" ) +private val primaryConstructorLoweringPhase = makeJsModulePhase( + ::PrimaryConstructorLowering, + name = "PrimaryConstructorLowering", + description = "Creates primary constructor if it doesn't exist", + prerequisite = setOf(enumClassConstructorLoweringPhase) +) + 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(enumClassConstructorLoweringPhase) + prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase) ) private val multipleCatchesLoweringPhase = makeJsModulePhase( @@ -394,6 +401,7 @@ val jsPhases = namedIrModulePhase( innerClassesLoweringPhase then innerClassConstructorCallsLoweringPhase then propertiesLoweringPhase then + primaryConstructorLoweringPhase then initializersLoweringPhase then // Common prefix ends moveBodilessDeclarationsToSeparatePlacePhase then diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrimaryConstructorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrimaryConstructorLowering.kt new file mode 100644 index 00000000000..aea662b9122 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrimaryConstructorLowering.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.builders.declarations.addConstructor +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall +import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + + +// Create primary constructor if it doesn't exist +class PrimaryConstructorLowering(context: CommonBackendContext) : ClassLoweringPass { + private val unitType = context.irBuiltIns.unitType + + override fun lower(irClass: IrClass) { + val constructors = irClass.declarations.filterIsInstance() + + if (constructors.any { it.isPrimary }) return + + val primary = createPrimaryConstructor(irClass) + + val initializeTransformer = object : IrElementTransformerVoid() { + override fun visitDeclaration(declaration: IrDeclaration) = declaration // optimize visiting + + override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) = expression.run { + IrDelegatingConstructorCallImpl(startOffset, endOffset, type, primary.symbol) + } + } + + constructors.forEach { it.transformChildrenVoid(initializeTransformer) } + } + + private object SYNTHETIC_PRIMARY_CONSTRUCTOR : IrDeclarationOriginImpl("SYNTHETIC_PRIMARY_CONSTRUCTOR") + + private fun createPrimaryConstructor(irClass: IrClass): IrConstructor { + val declaration = irClass.addConstructor { + origin = SYNTHETIC_PRIMARY_CONSTRUCTOR + isPrimary = true + visibility = Visibilities.PRIVATE + } + + declaration.body = irClass.run { + IrBlockBodyImpl(startOffset, endOffset, listOf(IrInstanceInitializerCallImpl(startOffset, endOffset, symbol, unitType))) + } + + return declaration + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 0515d30148c..e5e1fbfb234 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -35,7 +35,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo fun generate(): JsStatement { assert(!irClass.descriptor.isExpect) - maybeGeneratePrimaryConstructor() val transformer = IrDeclarationToJsTransformer() // Properties might be lowered out of classes @@ -134,15 +133,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo return null } - private fun maybeGeneratePrimaryConstructor() { - if (!irClass.declarations.any { it is IrConstructor }) { - val func = JsFunction(emptyScope, JsBlock(), "Ctor for ${irClass.name}") - func.name = className - classBlock.statements += func.makeStmt() - classModel.preDeclarationBlock.statements += generateInheritanceCode() - } - } - private fun generateInheritanceCode(): List { if (baseClass == null || baseClass.isAny()) { return emptyList()