From d625d9a988f3a7a344ce1687b085ff7c811e916c Mon Sep 17 00:00:00 2001 From: Artem Kobzar Date: Wed, 18 Oct 2023 13:29:15 +0000 Subject: [PATCH] [K/JS] Fix ES6-classes compilation for objects without constructor generated by plugins --- ...CollectClassDefaultConstructorsLowering.kt | 6 +-- .../ir/backend/js/lower/ObjectLowering.kt | 42 +++++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CollectClassDefaultConstructorsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CollectClassDefaultConstructorsLowering.kt index c2b37ae2dfc..df4dd231930 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CollectClassDefaultConstructorsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CollectClassDefaultConstructorsLowering.kt @@ -28,8 +28,8 @@ class CollectClassDefaultConstructorsLowering(private val context: JsIrBackendCo private val IrClass.defaultConstructor: IrConstructor? get() = constructors.singleOrNull { it.visibility == DescriptorVisibilities.PUBLIC && it.isDefaultConstructor() } +} - private fun IrFunction.isDefaultConstructor(): Boolean { - return valueParameters.isEmpty() || valueParameters.all { it.defaultValue != null } - } +fun IrFunction.isDefaultConstructor(): Boolean { + return valueParameters.isEmpty() || valueParameters.all { it.defaultValue != null } } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ObjectLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ObjectLowering.kt index a0a7f7da60c..1729f61fd15 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ObjectLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ObjectLowering.kt @@ -20,11 +20,12 @@ import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.backend.js.utils.getVoid import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.builders.declarations.addConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol +import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -59,8 +60,7 @@ class ObjectDeclarationLowering(val context: JsCommonBackendContext) : Declarati declaration.instanceField = instanceField - val primaryConstructor = declaration.primaryConstructor ?: declaration.syntheticPrimaryConstructor!! - + val primaryConstructor = declaration.findOrGenerateConstructorForObjectInstantiating() val initEntryInstancesFun = declaration.parent.safeAs()?.initEntryInstancesFun getInstanceFun.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { @@ -79,6 +79,42 @@ class ObjectDeclarationLowering(val context: JsCommonBackendContext) : Declarati return listOf(declaration, instanceField, getInstanceFun) } + // We need to generate the new synthetic constructor for ES6 classes in case if a plugin didn't create it. + // The constructor defined as SyntheticPrimaryConstructor is used as a constructor with an init block. + // Because it doesn't contain any [IrDelegatingConstructorCallImpl], we can't use it in ES-classes as constructor + private fun IrClass.findOrGenerateConstructorForObjectInstantiating(): IrConstructor { + val oldSyntheticPrimaryConstructor = primaryConstructor ?: syntheticPrimaryConstructor!! + if (!context.es6mode || !oldSyntheticPrimaryConstructor.isSyntheticPrimaryConstructor) return oldSyntheticPrimaryConstructor + + val declaration = addConstructor() + val superCtor = (superClass ?: context.irBuiltIns.anyClass.owner).constructors.first { it.isDefaultConstructor() } + + declaration.body = factory.createBlockBody( + startOffset, + endOffset, + listOf( + IrDelegatingConstructorCallImpl( + startOffset, + endOffset, + defaultType, + superCtor.symbol, + 0, + 0 + ), + IrDelegatingConstructorCallImpl( + startOffset, + endOffset, + defaultType, + oldSyntheticPrimaryConstructor.symbol, + 0, + 0 + ) + ) + ) + + return declaration + } + private fun IrBuilderWithScope.irNullabilityCheck(instanceField: IrField): IrExpression { val context = this@ObjectDeclarationLowering.context return if (context is JsIrBackendContext && context.es6mode) {