[JS BE] implement es6-classes's codegen
This commit is contained in:
@@ -15,14 +15,13 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAssociatedObjectAnnotatedAnnot
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun eliminateDeadDeclarations(
|
fun eliminateDeadDeclarations(
|
||||||
@@ -320,6 +319,22 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
|||||||
toStringMethod.enqueue("intrinsic: jsPlus")
|
toStringMethod.enqueue("intrinsic: jsPlus")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
context.intrinsics.jsConstruct -> {
|
||||||
|
val callType = expression.getTypeArgument(0)!!
|
||||||
|
val constructor = callType.getClass()!!.primaryConstructor
|
||||||
|
constructor!!.enqueue("ctor call from jsConstruct-intrinsic")
|
||||||
|
}
|
||||||
|
context.intrinsics.es6DefaultType -> {
|
||||||
|
//same as jsClass
|
||||||
|
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||||
|
ref.enqueue("intrinsic: jsClass")
|
||||||
|
referencedJsClasses += ref
|
||||||
|
|
||||||
|
//Generate klass in `val currResultType = resultType || klass`
|
||||||
|
val arg = expression.getTypeArgument(0)!!
|
||||||
|
val klass = arg.getClass()
|
||||||
|
constructedClasses.addIfNotNull(klass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.backend.js.*
|
import org.jetbrains.kotlin.ir.backend.js.*
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport
|
import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||||
@@ -79,7 +81,8 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
|||||||
|
|
||||||
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
||||||
if (!constructor.isPrimary) return null
|
if (!constructor.isPrimary) return null
|
||||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) + constructor.valueParameters
|
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
||||||
|
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
|
||||||
return ExportedConstructor(allValueParameters.map { exportParameter(it) })
|
return ExportedConstructor(allValueParameters.map { exportParameter(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -135,7 +135,11 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
return JsBinaryOperation(JsBinaryOperator.ASG, thisRef, arguments.single())
|
return JsBinaryOperation(JsBinaryOperator.ASG, thisRef, arguments.single())
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
return if (context.staticContext.backendContext.es6mode) {
|
||||||
|
JsInvocation(JsNameRef("super"), arguments)
|
||||||
|
} else {
|
||||||
|
JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall, context: JsGenerationContext): JsExpression {
|
override fun visitConstructorCall(expression: IrConstructorCall, context: JsGenerationContext): JsExpression {
|
||||||
|
|||||||
+38
-9
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||||
|
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
import org.jetbrains.kotlin.ir.types.isAny
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
@@ -31,25 +32,55 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
private val classBlock = JsGlobalBlock()
|
private val classBlock = JsGlobalBlock()
|
||||||
private val classModel = JsIrClassModel(irClass)
|
private val classModel = JsIrClassModel(irClass)
|
||||||
|
|
||||||
|
private val es6mode = context.staticContext.backendContext.es6mode
|
||||||
|
|
||||||
fun generate(): JsStatement {
|
fun generate(): JsStatement {
|
||||||
assert(!irClass.descriptor.isExpect)
|
assert(!irClass.descriptor.isExpect)
|
||||||
|
|
||||||
maybeGeneratePrimaryConstructor()
|
if (!es6mode) maybeGeneratePrimaryConstructor()
|
||||||
val transformer = IrDeclarationToJsTransformer()
|
val transformer = IrDeclarationToJsTransformer()
|
||||||
|
|
||||||
// Properties might be lowered out of classes
|
// Properties might be lowered out of classes
|
||||||
// We'll use IrSimpleFunction::correspondingProperty to collect them into set
|
// We'll use IrSimpleFunction::correspondingProperty to collect them into set
|
||||||
val properties = mutableSetOf<IrProperty>()
|
val properties = mutableSetOf<IrProperty>()
|
||||||
|
|
||||||
|
val jsClass = JsClass(name = className)
|
||||||
|
|
||||||
|
if (baseClass != null && !baseClass.isAny()) {
|
||||||
|
jsClass.baseClass = baseClassName?.makeRef()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es6mode) classModel.preDeclarationBlock.statements += jsClass.makeStmt()
|
||||||
|
|
||||||
for (declaration in irClass.declarations) {
|
for (declaration in irClass.declarations) {
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is IrConstructor -> {
|
is IrConstructor -> {
|
||||||
classBlock.statements += declaration.accept(transformer, context)
|
if (es6mode) {
|
||||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
declaration.accept(IrFunctionToJsTransformer(), context).let {
|
||||||
|
//HACK: add superCall to Error
|
||||||
|
if ((baseClass?.classifierOrNull?.owner as? IrClass)?.symbol === context.staticContext.backendContext.throwableClass) {
|
||||||
|
it.body.statements.add(0, JsInvocation(JsNameRef("super")).makeStmt())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.body.statements.any { it !is JsEmpty }) {
|
||||||
|
jsClass.constructor = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
classBlock.statements += declaration.accept(transformer, context)
|
||||||
|
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is IrSimpleFunction -> {
|
is IrSimpleFunction -> {
|
||||||
properties.addIfNotNull(declaration.correspondingPropertySymbol?.owner)
|
properties.addIfNotNull(declaration.correspondingPropertySymbol?.owner)
|
||||||
generateMemberFunction(declaration)?.let { classBlock.statements += it }
|
|
||||||
|
if (es6mode) {
|
||||||
|
val (_, function) = generateMemberFunction(declaration)
|
||||||
|
function?.let { jsClass.members += it }
|
||||||
|
} else {
|
||||||
|
val (memberRef, function) = generateMemberFunction(declaration)
|
||||||
|
function?.let { classBlock.statements += jsAssignment(memberRef, it.apply { name = null }).makeStmt() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is IrClass -> {
|
is IrClass -> {
|
||||||
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
||||||
@@ -111,17 +142,15 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
return this.overriddenSymbols.any { it.owner.overridesExternal() }
|
return this.overriddenSymbols.any { it.owner.overridesExternal() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? {
|
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsNameRef, JsFunction?> {
|
||||||
|
|
||||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||||
|
|
||||||
if (declaration.isReal && declaration.body != null) {
|
if (declaration.isReal && declaration.body != null) {
|
||||||
val translatedFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
val translatedFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
||||||
|
|
||||||
assert(!declaration.isStaticMethodOfClass)
|
assert(!declaration.isStaticMethodOfClass)
|
||||||
|
|
||||||
return jsAssignment(memberRef, translatedFunction.apply { name = null }).makeStmt()
|
return Pair(memberRef, translatedFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not generate code like
|
// do not generate code like
|
||||||
@@ -144,7 +173,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return Pair(memberRef, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeGeneratePrimaryConstructor() {
|
private fun maybeGeneratePrimaryConstructor() {
|
||||||
|
|||||||
+2
@@ -208,6 +208,8 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene
|
|||||||
val argument = expression.getValueArgument(index)
|
val argument = expression.getValueArgument(index)
|
||||||
val result = argument?.accept(transformer, context)
|
val result = argument?.accept(transformer, context)
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
if (context.staticContext.backendContext.es6mode) return@mapTo JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(2))
|
||||||
|
|
||||||
assert(expression is IrFunctionAccessExpression && expression.symbol.owner.isExternalOrInheritedFromExternal())
|
assert(expression is IrFunctionAccessExpression && expression.symbol.owner.isExternalOrInheritedFromExternal())
|
||||||
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||||
} else
|
} else
|
||||||
|
|||||||
Reference in New Issue
Block a user