[JS BE] implement es6-classes lowering
This commit is contained in:
@@ -228,7 +228,14 @@ private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeDe
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val throwableSuccessorsLoweringPhase = makeBodyLoweringPhase(
|
private val throwableSuccessorsLoweringPhase = makeBodyLoweringPhase(
|
||||||
::ThrowableLowering,
|
{ context ->
|
||||||
|
context.run {
|
||||||
|
val extendThrowableSymbol =
|
||||||
|
if (es6mode) setPropertiesToThrowableInstanceSymbol else extendThrowableSymbol
|
||||||
|
|
||||||
|
ThrowableLowering(this, extendThrowableSymbol)
|
||||||
|
}
|
||||||
|
},
|
||||||
name = "ThrowableLowering",
|
name = "ThrowableLowering",
|
||||||
description = "Link kotlin.Throwable and JavaScript Error together to provide proper interop between language and platform exceptions"
|
description = "Link kotlin.Throwable and JavaScript Error together to provide proper interop between language and platform exceptions"
|
||||||
)
|
)
|
||||||
@@ -517,6 +524,19 @@ private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val es6AddInternalParametersToConstructorPhase = makeBodyLoweringPhase(
|
||||||
|
::ES6AddInternalParametersToConstructorPhase,
|
||||||
|
name = "ES6CreateInitFunctionPhase",
|
||||||
|
description = "Add `box` and `resultType` params, create init functions for constructors"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6ConstructorLowering = makeBodyLoweringPhase(
|
||||||
|
::ES6ConstructorLowering,
|
||||||
|
name = "ES6ConstructorLoweringPhase",
|
||||||
|
description = "Lower constructors",
|
||||||
|
prerequisite = setOf(es6AddInternalParametersToConstructorPhase)
|
||||||
|
)
|
||||||
|
|
||||||
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||||
::SecondaryConstructorLowering,
|
::SecondaryConstructorLowering,
|
||||||
name = "SecondaryConstructorLoweringPhase",
|
name = "SecondaryConstructorLoweringPhase",
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ class JsMapping : DefaultMapping() {
|
|||||||
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
||||||
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
|
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
|
||||||
|
|
||||||
|
val constructorToInitFunction = newMapping<IrConstructor, IrSimpleFunction>()
|
||||||
|
|
||||||
val enumEntryToGetInstanceFun = newMapping<IrEnumEntry, IrSimpleFunction>()
|
val enumEntryToGetInstanceFun = newMapping<IrEnumEntry, IrSimpleFunction>()
|
||||||
val enumEntryToInstanceField = newMapping<IrEnumEntry, IrField>()
|
val enumEntryToInstanceField = newMapping<IrEnumEntry, IrField>()
|
||||||
val enumConstructorToNewConstructor = newMapping<IrConstructor, IrConstructor>()
|
val enumConstructorToNewConstructor = newMapping<IrConstructor, IrConstructor>()
|
||||||
|
|||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.isAny
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add ES6_INIT_BOX_PARAMETER for each constructor (except constructors
|
||||||
|
* of inline, external and primitive (string, arrays) classes).
|
||||||
|
* Uses: Inline class's constructor initialize field of outer class before
|
||||||
|
* call `super`, but its impossible in ES6. ES6_INIT_BOX_PARAMETER - object,
|
||||||
|
* that collect these values and pass to super constructor. In the last
|
||||||
|
* constructor of delegation chain ES6_INIT_BOX_PARAMETER will be open
|
||||||
|
* with `Object.assign(this, box)`
|
||||||
|
*
|
||||||
|
* Add ES6_RESULT_TYPE PARAMETER for each secondary ctor (except
|
||||||
|
* constructors of external and primitive (string, arrays) classes).
|
||||||
|
* Uses: Pass information about type of new object to `Reflect.construct()`
|
||||||
|
*
|
||||||
|
* Transform SYNTHETIC_PRIMARY_CONSTRUCTOR:
|
||||||
|
* constructor() {
|
||||||
|
* //statements
|
||||||
|
* }
|
||||||
|
* ==>
|
||||||
|
* constructor() {
|
||||||
|
* init(this)
|
||||||
|
* }
|
||||||
|
* init($this$) {
|
||||||
|
* //statements from ctor
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
class ES6AddInternalParametersToConstructorPhase(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
object ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION")
|
||||||
|
object ES6_INIT_BOX_PARAMETER : IrDeclarationOriginImpl("ES6_INIT_BOX_PARAMETER")
|
||||||
|
object ES6_RESULT_TYPE_PARAMETER : IrDeclarationOriginImpl("ES6_RESULT_TYPE_PARAMETER")
|
||||||
|
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
assert(context.es6mode)
|
||||||
|
|
||||||
|
container.transform(CallSiteTransformer(), null)
|
||||||
|
|
||||||
|
if (container !is IrConstructor) return
|
||||||
|
|
||||||
|
if (!container.hasStrictSignature()) container.addInternalValueParameters()
|
||||||
|
|
||||||
|
if (container.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) {
|
||||||
|
createInitFunction(container)
|
||||||
|
openInitializerBox(container)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrConstructor.addInternalValueParameters() {
|
||||||
|
addValueParameter("box", context.dynamicType, ES6_INIT_BOX_PARAMETER)
|
||||||
|
|
||||||
|
if (!isPrimary) {
|
||||||
|
addValueParameter("resultType", context.dynamicType, ES6_RESULT_TYPE_PARAMETER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createInitFunction(constructor: IrConstructor) {
|
||||||
|
val irClass = constructor.parentAsClass
|
||||||
|
val initFunction = buildInitFunction(constructor, irClass)
|
||||||
|
irClass.declarations += initFunction
|
||||||
|
|
||||||
|
context.mapping.constructorToInitFunction[constructor] = initFunction
|
||||||
|
|
||||||
|
initFunction.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||||
|
declaration.parent = initFunction
|
||||||
|
return declaration
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openInitializerBox(constructor: IrConstructor) = with(constructor.body as IrBlockBody) {
|
||||||
|
statements.clear()
|
||||||
|
statements += JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
||||||
|
it.putValueArgument(0, JsIrBuilder.buildGetValue(constructor.parentAsClass.thisReceiver!!.symbol))
|
||||||
|
it.putValueArgument(1, JsIrBuilder.buildGetValue(constructor.valueParameters.last().symbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildInitFunction(constructor: IrConstructor, irClass: IrClass): IrSimpleFunction {
|
||||||
|
val functionName = "${irClass.name}_init"
|
||||||
|
|
||||||
|
return JsIrBuilder.buildFunction(
|
||||||
|
functionName,
|
||||||
|
context.irBuiltIns.unitType,
|
||||||
|
irClass,
|
||||||
|
Visibilities.PROTECTED,
|
||||||
|
Modality.FINAL,
|
||||||
|
constructor.isInline,
|
||||||
|
constructor.isExternal,
|
||||||
|
origin = ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION
|
||||||
|
).apply {
|
||||||
|
addValueParameter("\$this\$", context.dynamicType)
|
||||||
|
|
||||||
|
body = JsIrBuilder.buildBlockBody(constructor.body?.statements ?: emptyList())
|
||||||
|
|
||||||
|
transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
||||||
|
with(expression) { IrGetValueImpl(startOffset, endOffset, type, valueParameters.single().symbol) }
|
||||||
|
} else {
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass `null` for ES6_INIT_BOX_PARAMETER and ES6_RESULT_TYPE_PARAMETER
|
||||||
|
*/
|
||||||
|
inner class CallSiteTransformer : IrElementTransformerVoid() {
|
||||||
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
|
val constructor = expression.symbol.owner
|
||||||
|
val parent = constructor.parentAsClass
|
||||||
|
|
||||||
|
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
||||||
|
|
||||||
|
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
||||||
|
return expression.run {
|
||||||
|
IrConstructorCallImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
type,
|
||||||
|
symbol,
|
||||||
|
typeArgumentsCount,
|
||||||
|
constructorTypeArgumentsCount,
|
||||||
|
valueArgumentsCount + newArgsCount
|
||||||
|
).also {
|
||||||
|
for (i in 0 until valueArgumentsCount) {
|
||||||
|
it.putValueArgument(i, getValueArgument(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
it.putValueArgument(
|
||||||
|
valueArgumentsCount,
|
||||||
|
JsIrBuilder.buildNull(context.dynamicType)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!constructor.isPrimary) {
|
||||||
|
it.putValueArgument(
|
||||||
|
valueArgumentsCount + 1,
|
||||||
|
JsIrBuilder.buildNull(context.dynamicType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
val constructor = expression.symbol.owner
|
||||||
|
val parent = constructor.parentAsClass
|
||||||
|
|
||||||
|
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
||||||
|
|
||||||
|
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
||||||
|
|
||||||
|
return expression.run {
|
||||||
|
IrDelegatingConstructorCallImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
type,
|
||||||
|
symbol,
|
||||||
|
typeArgumentsCount,
|
||||||
|
valueArgumentsCount + newArgsCount
|
||||||
|
).also {
|
||||||
|
for (i in 0 until valueArgumentsCount) {
|
||||||
|
it.putValueArgument(i, getValueArgument(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
it.putValueArgument(
|
||||||
|
valueArgumentsCount,
|
||||||
|
JsIrBuilder.buildNull(context.dynamicType)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!constructor.isPrimary) {
|
||||||
|
it.putValueArgument(
|
||||||
|
valueArgumentsCount + 1,
|
||||||
|
JsIrBuilder.buildNull(context.dynamicType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||||
|
val primitives = with(context.irBuiltIns) { primitiveArrays + stringClass }
|
||||||
|
return with(parentAsClass) { isExternal || isInline || symbol in primitives }
|
||||||
|
}
|
||||||
|
}
|
||||||
+565
@@ -0,0 +1,565 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
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.backend.js.lower.ES6AddInternalParametersToConstructorPhase.*
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.isAny
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
|
object ES6_THIS_VARIABLE_ORIGIN : IrDeclarationOriginImpl("ES6_THIS_VARIABLE_ORIGIN")
|
||||||
|
|
||||||
|
class ES6ConstructorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
assert(context.es6mode)
|
||||||
|
|
||||||
|
if (container !is IrConstructor) return
|
||||||
|
|
||||||
|
if (container.hasStrictSignature()) return
|
||||||
|
|
||||||
|
hackEnums(container)
|
||||||
|
hackExceptions(context, container)
|
||||||
|
|
||||||
|
val superCall = getSuperCall(container) ?: return
|
||||||
|
val superCtor = superCall.symbol.owner
|
||||||
|
val helper = LowerCtorHelper(context, container, superCtor)
|
||||||
|
|
||||||
|
if (container.isPrimary) {
|
||||||
|
if (superCtor.isPrimary) primaryToPrimary(helper)
|
||||||
|
else primaryToSecondary(helper)
|
||||||
|
} else {
|
||||||
|
if (superCtor.isPrimary) secondaryToPrimary(helper)
|
||||||
|
else secondaryToSecondary(helper)
|
||||||
|
|
||||||
|
replaceCallToDefaultPrimary(context, container)
|
||||||
|
changeIrConstructorToIrFunction(context, container)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor(args, box) {
|
||||||
|
* var currBox = box || {}
|
||||||
|
*
|
||||||
|
* //1. Superclass is Any
|
||||||
|
* Object.assign(this, currBox)
|
||||||
|
* //body
|
||||||
|
*
|
||||||
|
* //2. Base class isInline or isExternal or array/string
|
||||||
|
* super(args)
|
||||||
|
* Object.assign(this, currBox)
|
||||||
|
* //body
|
||||||
|
*
|
||||||
|
* //3. Base class !isInline and !isExternal and !(array/string)
|
||||||
|
* //fill initialization box
|
||||||
|
* super(args, currBox)
|
||||||
|
* //body
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private fun primaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
||||||
|
statements.add(0, boxOrEmptyObject)
|
||||||
|
|
||||||
|
if (superCtor.parentAsClass.defaultType.isAny()) {
|
||||||
|
//after superCall
|
||||||
|
statements.add(1, openBoxStatement(thisSymbol, boxSymbol))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superCtor.hasStrictSignature()) {
|
||||||
|
//after superCall
|
||||||
|
statements.add(2, openBoxStatement(thisSymbol, boxSymbol))
|
||||||
|
} else {
|
||||||
|
fillInitializerBox(boxSymbol, constructor)
|
||||||
|
putBoxToSuperCall(boxSymbol, constructor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor(args, box) {
|
||||||
|
* var currBox = box || {}
|
||||||
|
*
|
||||||
|
* //1. Base class isExternal or array/string
|
||||||
|
* var $this$ = Base_constructor(.., currBox)
|
||||||
|
* Object.assign(this, currBox)
|
||||||
|
* return $this$
|
||||||
|
*
|
||||||
|
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||||
|
* //fill initialization box
|
||||||
|
* var $this$ = Base_constructor(.., currBox, new.target)
|
||||||
|
* //body
|
||||||
|
* return $this$
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private fun primaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
||||||
|
statements.add(0, boxOrEmptyObject)
|
||||||
|
|
||||||
|
if (superCtor.hasStrictSignature()) {
|
||||||
|
fun createNewSuperCall(): IrCall {
|
||||||
|
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
||||||
|
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||||
|
val args = IrVarargImpl(
|
||||||
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||||
|
context.dynamicType,
|
||||||
|
context.dynamicType,
|
||||||
|
getElements(constructor)
|
||||||
|
)
|
||||||
|
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct).apply {
|
||||||
|
putValueArgument(0, callType)
|
||||||
|
putValueArgument(1, newTarget)
|
||||||
|
putValueArgument(2, args)
|
||||||
|
|
||||||
|
putTypeArgument(0, superCtor.returnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newThis = createThisVariable(createNewSuperCall())
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements.add(2, openBoxStatement(newThis.symbol, boxSymbol))
|
||||||
|
statements += returnThis(constructor, newThis)
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
} else {
|
||||||
|
putBoxToSuperCall(boxSymbol, constructor)
|
||||||
|
fillInitializerBox(boxSymbol, constructor)
|
||||||
|
|
||||||
|
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||||
|
val newThis = createThisVariable(createNewSuperCallPrimaryToSecondary(superCall, newTarget))
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements += returnThis(constructor, newThis)
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived_constructor(.., box, resultType) {
|
||||||
|
* var currBox = box || {}
|
||||||
|
* var currResultType = resultType || Derived
|
||||||
|
*
|
||||||
|
* //1. Base class isInline or isExternal or array/string
|
||||||
|
* var $this$ = construct(Base, currResultType, [..])
|
||||||
|
* Object.assign(this, currBox)
|
||||||
|
* //body
|
||||||
|
* return $this$
|
||||||
|
*
|
||||||
|
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||||
|
* //fill initialization box
|
||||||
|
* var $this$ = construct(Base, currResultType, [.., currBox])
|
||||||
|
* //body
|
||||||
|
* return $this$
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private fun secondaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
||||||
|
statements.add(0, boxOrEmptyObject)
|
||||||
|
statements.add(1, resultTypeOrDefaultType())
|
||||||
|
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
||||||
|
|
||||||
|
if (superCtor.hasStrictSignature()) {
|
||||||
|
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol))
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
||||||
|
statements.add(returnThis(constructor, newThis))
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
} else {
|
||||||
|
fillInitializerBox(boxSymbol, constructor)
|
||||||
|
|
||||||
|
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol, boxSymbol))
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements.add(returnThis(constructor, newThis))
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived_constructor(.., box, resultType) {
|
||||||
|
* var currBox = box || {}
|
||||||
|
* var currResultType = resultType || Derived
|
||||||
|
* //fill initialization box
|
||||||
|
*
|
||||||
|
* //1. Base class isInline or isExternal or array/string
|
||||||
|
* var $this$ = Base_constructor(..)
|
||||||
|
* Object.assign(this, currBox)
|
||||||
|
* //body
|
||||||
|
* return $this$
|
||||||
|
*
|
||||||
|
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||||
|
* var $this$ = Base_constructor(.., currBox, currResultType)
|
||||||
|
* //body
|
||||||
|
* return $this$
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private fun secondaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
||||||
|
statements.add(0, boxOrEmptyObject)
|
||||||
|
statements.add(1, resultTypeOrDefaultType())
|
||||||
|
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
||||||
|
|
||||||
|
putBoxToSuperCall(boxSymbol, constructor)
|
||||||
|
fillInitializerBox(boxSymbol, constructor)
|
||||||
|
|
||||||
|
if (superCtor.hasStrictSignature()) {
|
||||||
|
val newThis = createThisVariable(superCall)
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
||||||
|
statements += returnThis(constructor, newThis)
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
} else {
|
||||||
|
val newThis = createThisVariable(createNewSuperCallSecondaryToSecondary(superCall, boxSymbol, resultTypeSymbol))
|
||||||
|
changeReturnUnitToReturnInstance(newThis)
|
||||||
|
|
||||||
|
statements += returnThis(constructor, newThis)
|
||||||
|
|
||||||
|
redirectOldThisToNewOne(constructor, newThis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//superCallBuilder
|
||||||
|
private fun createNewSuperCallSecondaryToSecondary(
|
||||||
|
superCall: IrDelegatingConstructorCall,
|
||||||
|
boxSymbol: IrValueSymbol,
|
||||||
|
resultTypeSymbol: IrVariableSymbol
|
||||||
|
) = superCall.apply {
|
||||||
|
putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol))
|
||||||
|
putValueArgument(ES6_RESULT_TYPE_PARAMETER, JsIrBuilder.buildGetValue(resultTypeSymbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
//superCallBuilder
|
||||||
|
private fun createNewSuperCallPrimaryToSecondary(
|
||||||
|
superCall: IrDelegatingConstructorCall,
|
||||||
|
newTarget: IrCall? = null
|
||||||
|
) = superCall.apply { putValueArgument(ES6_RESULT_TYPE_PARAMETER, newTarget) }
|
||||||
|
|
||||||
|
private fun IrDelegatingConstructorCall.putValueArgument(origin: IrDeclarationOrigin, value: IrExpression?) {
|
||||||
|
val valueParameters = symbol.owner.valueParameters
|
||||||
|
for (i in valueParameters.indices) {
|
||||||
|
if (valueParameters[i].origin === origin) {
|
||||||
|
putValueArgument(i, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//superCallBuilder
|
||||||
|
private fun createNewSuperCallSecondaryToPrimary(
|
||||||
|
constructor: IrConstructor,
|
||||||
|
superCtor: IrConstructor,
|
||||||
|
resultTypeSymbol: IrVariableSymbol,
|
||||||
|
boxSymbol: IrVariableSymbol? = null
|
||||||
|
): IrCall {
|
||||||
|
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
||||||
|
val resultType = JsIrBuilder.buildGetValue(resultTypeSymbol)
|
||||||
|
val arguments = IrVarargImpl(
|
||||||
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||||
|
context.irBuiltIns.anyNType,
|
||||||
|
context.irBuiltIns.anyNType,
|
||||||
|
getElements(constructor, boxSymbol)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (superCtor.parentAsClass.defaultType.isAny()) {
|
||||||
|
//superType is Any, and we have default primary --> create call to default primary
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
||||||
|
arguments.elements.clear()
|
||||||
|
arguments.addElement(JsIrBuilder.buildGetValue(boxSymbol!!))
|
||||||
|
|
||||||
|
putValueArgument(0, JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(constructor.returnType)))
|
||||||
|
putValueArgument(1, resultType)
|
||||||
|
putValueArgument(2, arguments)
|
||||||
|
|
||||||
|
putTypeArgument(0, constructor.returnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
||||||
|
putValueArgument(0, callType)
|
||||||
|
putValueArgument(1, resultType)
|
||||||
|
putValueArgument(2, arguments)
|
||||||
|
|
||||||
|
putTypeArgument(0, superCtor.returnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy arguments from superCall
|
||||||
|
*/
|
||||||
|
private fun getElements(constructor: IrConstructor, boxSymbol: IrValueSymbol? = null): List<IrVarargElement> {
|
||||||
|
val result = mutableListOf<IrVarargElement>()
|
||||||
|
|
||||||
|
val superCall = constructor.body!!.statements.filterIsInstance<IrDelegatingConstructorCall>().first()
|
||||||
|
repeat(superCall.valueArgumentsCount) { i ->
|
||||||
|
val arg = superCall.getValueArgument(i) ?: return@repeat
|
||||||
|
if (superCall.symbol.owner.valueParameters[i].origin === ES6_INIT_BOX_PARAMETER) {
|
||||||
|
result += JsIrBuilder.buildGetValue(boxSymbol!!)
|
||||||
|
} else {
|
||||||
|
if (arg.type.getInlinedClass() != null) {
|
||||||
|
val any = context.irBuiltIns.anyNType
|
||||||
|
result += JsIrBuilder.buildTypeOperator(any, IrTypeOperator.REINTERPRET_CAST, arg, any)
|
||||||
|
} else {
|
||||||
|
result += arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
//builder
|
||||||
|
private fun returnThis(constructor: IrConstructor, newThis: IrVariable): IrReturn {
|
||||||
|
return JsIrBuilder.buildReturn(
|
||||||
|
constructor.symbol,
|
||||||
|
JsIrBuilder.buildGetValue(newThis.symbol),
|
||||||
|
context.irBuiltIns.nothingType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform statements like `this.x = y` to `box.x = y`
|
||||||
|
*/
|
||||||
|
private fun fillInitializerBox(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
||||||
|
val statements = (constructor.body as IrBlockBody).statements
|
||||||
|
for (i in statements.indices) {
|
||||||
|
val current = statements[i]
|
||||||
|
if (current is IrSetField) {
|
||||||
|
if ((current.receiver as? IrGetValue)?.symbol?.owner === constructor.parentAsClass.thisReceiver) {
|
||||||
|
current.receiver = JsIrBuilder.buildGetValue(boxSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statements[i] is IrDelegatingConstructorCall) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//transformer
|
||||||
|
private fun putBoxToSuperCall(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
||||||
|
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
return expression.also { it.putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol)) }
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//builder
|
||||||
|
private fun openBoxStatement(thisSymbol: IrValueSymbol, boxSymbol: IrValueSymbol): IrCall {
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
||||||
|
it.putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
||||||
|
it.putValueArgument(1, JsIrBuilder.buildGetValue(boxSymbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//util
|
||||||
|
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||||
|
val primitives = with(context.irBuiltIns) { primitiveArrays + stringClass }
|
||||||
|
return with(parentAsClass) { isExternal || isInline || symbol in primitives }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//transformer
|
||||||
|
private fun replaceCallToDefaultPrimary(context: JsIrBackendContext, constructor: IrConstructor) {
|
||||||
|
val thisSymbol = (((constructor.body as IrBlockBody).statements
|
||||||
|
.find { it is IrVariable && it.origin === ES6_THIS_VARIABLE_ORIGIN }) as IrVariable?)?.symbol ?: return
|
||||||
|
|
||||||
|
(constructor.body as IrBlockBody).statements.transform {
|
||||||
|
if (it is IrDelegatingConstructorCall) {
|
||||||
|
val superCtor = it.symbol.owner
|
||||||
|
val initFunc = context.mapping.constructorToInitFunction[superCtor]!!
|
||||||
|
|
||||||
|
JsIrBuilder.buildCall(initFunc.symbol).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
||||||
|
}
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//transformer
|
||||||
|
private fun redirectOldThisToNewOne(constructor: IrConstructor, newThis: IrVariable) {
|
||||||
|
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
||||||
|
with(expression) { IrGetValueImpl(startOffset, endOffset, type, newThis.symbol) }
|
||||||
|
} else {
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change `return Unit` to `return $this$`
|
||||||
|
*/
|
||||||
|
private fun LowerCtorHelper.changeReturnUnitToReturnInstance(newThis: IrVariable) {
|
||||||
|
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
return JsIrBuilder.buildReturn(
|
||||||
|
constructor.symbol,
|
||||||
|
JsIrBuilder.buildGetValue(newThis.symbol),
|
||||||
|
expression.type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hackEnums(constructor: IrConstructor) {
|
||||||
|
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||||
|
return (expression.argument as? IrDelegatingConstructorCall) ?: expression
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap call synthetic primary ctor and call extendThrowable
|
||||||
|
*/
|
||||||
|
private fun hackExceptions(context: JsIrBackendContext, constructor: IrConstructor) {
|
||||||
|
val setPropertiesSymbol = context.setPropertiesToThrowableInstanceSymbol
|
||||||
|
|
||||||
|
val statements = (constructor.body as IrBlockBody).statements
|
||||||
|
|
||||||
|
var callIndex = -1
|
||||||
|
var superCallIndex = -1
|
||||||
|
for (i in statements.indices) {
|
||||||
|
val s = statements[i]
|
||||||
|
|
||||||
|
if (s is IrCall && s.symbol === setPropertiesSymbol) callIndex = i
|
||||||
|
if (s is IrDelegatingConstructorCall && s.symbol.owner.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) superCallIndex = i
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callIndex != -1 && superCallIndex != -1) {
|
||||||
|
val tmp = statements[callIndex]
|
||||||
|
statements[callIndex] = statements[superCallIndex]
|
||||||
|
statements[superCallIndex] = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LowerCtorHelper(
|
||||||
|
private val context: JsIrBackendContext,
|
||||||
|
val constructor: IrConstructor,
|
||||||
|
val superCtor: IrConstructor
|
||||||
|
) {
|
||||||
|
private val boxParameterSymbol = constructor.valueParameters.find { it.origin === ES6_INIT_BOX_PARAMETER }!!.symbol
|
||||||
|
val resultTypeParameterSymbol by lazy {
|
||||||
|
constructor.valueParameters.find { it.origin === ES6_RESULT_TYPE_PARAMETER }!!.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
val statements = (constructor.body as IrBlockBody).statements
|
||||||
|
|
||||||
|
/**
|
||||||
|
* var currBox = box || {}
|
||||||
|
*/
|
||||||
|
val boxOrEmptyObject = boxOrEmptyObject(boxParameterSymbol, constructor)
|
||||||
|
private fun boxOrEmptyObject(boxSymbol: IrValueSymbol, parent: IrConstructor): IrVariable {
|
||||||
|
val emptyObject = JsIrBuilder.buildCall(context.intrinsics.jsEmptyObject)
|
||||||
|
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(boxSymbol))
|
||||||
|
putValueArgument(1, emptyObject)
|
||||||
|
}
|
||||||
|
return JsIrBuilder.buildVar(context.dynamicType, parent, "currBox", initializer = or)
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxSymbol = boxOrEmptyObject.symbol
|
||||||
|
val thisSymbol = constructor.parentAsClass.thisReceiver!!.symbol
|
||||||
|
|
||||||
|
val superCall: IrDelegatingConstructorCall by lazy { getSuperCall(constructor)!! }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* var $this$ = `newSuperCall`
|
||||||
|
*/
|
||||||
|
fun createThisVariable(newSuperCall: IrExpression): IrVariable {
|
||||||
|
val newThis = JsIrBuilder.buildVar(
|
||||||
|
context.dynamicType,
|
||||||
|
constructor,
|
||||||
|
"\$this\$",
|
||||||
|
initializer = newSuperCall
|
||||||
|
).apply {
|
||||||
|
origin = ES6_THIS_VARIABLE_ORIGIN
|
||||||
|
}
|
||||||
|
|
||||||
|
(constructor.body as IrBlockBody).statements.transform {
|
||||||
|
if (it === superCall) newThis
|
||||||
|
else it
|
||||||
|
}
|
||||||
|
|
||||||
|
return newThis
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* var currResultType = resultType || D
|
||||||
|
*/
|
||||||
|
fun resultTypeOrDefaultType(): IrStatement {
|
||||||
|
val defaultType = JsIrBuilder.buildCall(context.intrinsics.es6DefaultType).apply {
|
||||||
|
putTypeArgument(0, constructor.parentAsClass.defaultType)
|
||||||
|
}
|
||||||
|
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(resultTypeParameterSymbol))
|
||||||
|
putValueArgument(1, defaultType)
|
||||||
|
}
|
||||||
|
return JsIrBuilder.buildVar(context.dynamicType, constructor, "currResultType", initializer = or)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSuperCall(constructor: IrConstructor): IrDelegatingConstructorCall? {
|
||||||
|
var result: IrDelegatingConstructorCall? = null
|
||||||
|
(constructor.body as IrBlockBody).acceptChildren(object : IrElementVisitor<Unit, Any?> {
|
||||||
|
override fun visitElement(element: IrElement, data: Any?) { }
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock, data: Any?) {
|
||||||
|
expression.statements.forEach { it.accept(this, data) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Any?) {
|
||||||
|
result = result ?: expression
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeIrConstructorToIrFunction(context: JsIrBackendContext, container: IrConstructor) {
|
||||||
|
val newConstructor = JsIrBuilder.buildFunction(
|
||||||
|
"${container.parentAsClass.name}_constructor",
|
||||||
|
container.returnType,
|
||||||
|
container.parent
|
||||||
|
).apply {
|
||||||
|
container.valueParameters.forEach { param ->
|
||||||
|
addValueParameter(param.name.asString(), param.type, param.origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
val parametersMap = container.valueParameters.zip(valueParameters).toMap()
|
||||||
|
body = container.body
|
||||||
|
transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
val newParam = parametersMap[expression.symbol.owner]
|
||||||
|
return if (newParam != null) JsIrBuilder.buildGetValue(newParam.symbol) else expression
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
container.parentAsClass.declarations.transform {
|
||||||
|
if (it === container) newConstructor else it
|
||||||
|
}
|
||||||
|
|
||||||
|
context.mapping.secondaryConstructorToDelegate[container] = newConstructor
|
||||||
|
}
|
||||||
+1
-1
@@ -38,7 +38,7 @@ class PrimaryConstructorLowering(context: JsCommonBackendContext) : DeclarationT
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private object SYNTHETIC_PRIMARY_CONSTRUCTOR : IrDeclarationOriginImpl("SYNTHETIC_PRIMARY_CONSTRUCTOR")
|
object SYNTHETIC_PRIMARY_CONSTRUCTOR : IrDeclarationOriginImpl("SYNTHETIC_PRIMARY_CONSTRUCTOR")
|
||||||
|
|
||||||
private val unitType = context.irBuiltIns.unitType
|
private val unitType = context.irBuiltIns.unitType
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|||||||
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
assert(!context.es6mode)
|
||||||
|
|
||||||
if (declaration is IrConstructor && !declaration.isPrimary) {
|
if (declaration is IrConstructor && !declaration.isPrimary) {
|
||||||
val irClass = declaration.parentAsClass
|
val irClass = declaration.parentAsClass
|
||||||
@@ -228,7 +229,10 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
|
|
||||||
val target = expression.symbol.owner
|
val target = expression.symbol.owner
|
||||||
return if (target.isSecondaryConstructorCall) {
|
return if (target.isSecondaryConstructorCall) {
|
||||||
val factory = context.buildConstructorFactory(target, target.parentAsClass)
|
val factory = with(context) {
|
||||||
|
if (es6mode) mapping.secondaryConstructorToDelegate[target] ?: error("Not found IrFunction for secondary ctor")
|
||||||
|
else buildConstructorFactory(target, target.parentAsClass)
|
||||||
|
}
|
||||||
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
||||||
} else expression
|
} else expression
|
||||||
}
|
}
|
||||||
@@ -240,8 +244,14 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
|
|
||||||
return if (target.isSecondaryConstructorCall) {
|
return if (target.isSecondaryConstructorCall) {
|
||||||
val klass = target.parentAsClass
|
val klass = target.parentAsClass
|
||||||
val delegate = context.buildConstructorDelegate(target, klass)
|
val delegate = with(context) {
|
||||||
|
if (es6mode) mapping.secondaryConstructorToDelegate[target] ?: error("Not found IrFunction for secondary ctor")
|
||||||
|
else buildConstructorDelegate(target, klass)
|
||||||
|
}
|
||||||
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
||||||
|
if (context.es6mode) {
|
||||||
|
return newCall
|
||||||
|
}
|
||||||
|
|
||||||
val readThis = expression.run {
|
val readThis = expression.run {
|
||||||
if (data!! is IrConstructor) {
|
if (data!! is IrConstructor) {
|
||||||
|
|||||||
+5
-2
@@ -13,18 +13,21 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.isNullableString
|
import org.jetbrains.kotlin.ir.types.isNullableString
|
||||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
|
||||||
|
|
||||||
class ThrowableLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
class ThrowableLowering(
|
||||||
|
val context: JsIrBackendContext,
|
||||||
|
val extendThrowableFunction: IrSimpleFunctionSymbol
|
||||||
|
) : BodyLoweringPass {
|
||||||
private val nothingNType get() = context.irBuiltIns.nothingNType
|
private val nothingNType get() = context.irBuiltIns.nothingNType
|
||||||
|
|
||||||
private val throwableConstructors = context.throwableConstructors
|
private val throwableConstructors = context.throwableConstructors
|
||||||
private val newThrowableFunction = context.newThrowableSymbol
|
private val newThrowableFunction = context.newThrowableSymbol
|
||||||
private val extendThrowableFunction = context.extendThrowableSymbol
|
|
||||||
|
|
||||||
fun nullValue(): IrExpression = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, nothingNType)
|
fun nullValue(): IrExpression = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, nothingNType)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user