[JS IR BE] Properly handle primary constructors
- force primary constructor to be created by codegen - make sure initializer is invoked once in primary constructor - make one of coroutine constructor primary - remove hack from codegen
This commit is contained in:
+1
-1
@@ -392,7 +392,7 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
|||||||
coroutineClass.defaultType,
|
coroutineClass.defaultType,
|
||||||
isInline = false,
|
isInline = false,
|
||||||
isExternal = false,
|
isExternal = false,
|
||||||
isPrimary = false
|
isPrimary = true
|
||||||
).apply {
|
).apply {
|
||||||
d.bind(this)
|
d.bind(this)
|
||||||
parent = coroutineClass
|
parent = coroutineClass
|
||||||
|
|||||||
@@ -275,9 +275,7 @@ class JsIrBackendContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val throwableConstructors by lazy { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } }
|
val throwableConstructors by lazy { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().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<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> {
|
private fun referenceOperators(): Map<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> {
|
||||||
val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
|
val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
|
||||||
|
|||||||
@@ -260,11 +260,18 @@ private val propertiesLoweringPhase = makeJsModulePhase(
|
|||||||
description = "Move fields and accessors out from its property"
|
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(
|
private val initializersLoweringPhase = makeCustomJsModulePhase(
|
||||||
{ context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
|
{ context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
|
||||||
name = "InitializersLowering",
|
name = "InitializersLowering",
|
||||||
description = "Merge init block and field initializers into [primary] constructor",
|
description = "Merge init block and field initializers into [primary] constructor",
|
||||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val multipleCatchesLoweringPhase = makeJsModulePhase(
|
private val multipleCatchesLoweringPhase = makeJsModulePhase(
|
||||||
@@ -394,6 +401,7 @@ val jsPhases = namedIrModulePhase(
|
|||||||
innerClassesLoweringPhase then
|
innerClassesLoweringPhase then
|
||||||
innerClassConstructorCallsLoweringPhase then
|
innerClassConstructorCallsLoweringPhase then
|
||||||
propertiesLoweringPhase then
|
propertiesLoweringPhase then
|
||||||
|
primaryConstructorLoweringPhase then
|
||||||
initializersLoweringPhase then
|
initializersLoweringPhase then
|
||||||
// Common prefix ends
|
// Common prefix ends
|
||||||
moveBodilessDeclarationsToSeparatePlacePhase then
|
moveBodilessDeclarationsToSeparatePlacePhase then
|
||||||
|
|||||||
+62
@@ -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<IrConstructor>()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
-10
@@ -35,7 +35,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
fun generate(): JsStatement {
|
fun generate(): JsStatement {
|
||||||
assert(!irClass.descriptor.isExpect)
|
assert(!irClass.descriptor.isExpect)
|
||||||
|
|
||||||
maybeGeneratePrimaryConstructor()
|
|
||||||
val transformer = IrDeclarationToJsTransformer()
|
val transformer = IrDeclarationToJsTransformer()
|
||||||
|
|
||||||
// Properties might be lowered out of classes
|
// Properties might be lowered out of classes
|
||||||
@@ -134,15 +133,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
return null
|
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<JsStatement> {
|
private fun generateInheritanceCode(): List<JsStatement> {
|
||||||
if (baseClass == null || baseClass.isAny()) {
|
if (baseClass == null || baseClass.isAny()) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
|||||||
Reference in New Issue
Block a user