[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.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
fun eliminateDeadDeclarations(
|
||||
@@ -320,6 +319,22 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
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.Visibilities
|
||||
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.isJsExport
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||
@@ -79,7 +81,8 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
||||
|
||||
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
||||
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) })
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -135,7 +135,11 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
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 {
|
||||
|
||||
+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.types.IrType
|
||||
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.util.*
|
||||
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 classModel = JsIrClassModel(irClass)
|
||||
|
||||
private val es6mode = context.staticContext.backendContext.es6mode
|
||||
|
||||
fun generate(): JsStatement {
|
||||
assert(!irClass.descriptor.isExpect)
|
||||
|
||||
maybeGeneratePrimaryConstructor()
|
||||
if (!es6mode) maybeGeneratePrimaryConstructor()
|
||||
val transformer = IrDeclarationToJsTransformer()
|
||||
|
||||
// Properties might be lowered out of classes
|
||||
// We'll use IrSimpleFunction::correspondingProperty to collect them into set
|
||||
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) {
|
||||
when (declaration) {
|
||||
is IrConstructor -> {
|
||||
classBlock.statements += declaration.accept(transformer, context)
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
if (es6mode) {
|
||||
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 -> {
|
||||
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 -> {
|
||||
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() }
|
||||
}
|
||||
|
||||
private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? {
|
||||
|
||||
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsNameRef, JsFunction?> {
|
||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
|
||||
if (declaration.isReal && declaration.body != null) {
|
||||
val translatedFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
||||
|
||||
assert(!declaration.isStaticMethodOfClass)
|
||||
|
||||
return jsAssignment(memberRef, translatedFunction.apply { name = null }).makeStmt()
|
||||
return Pair(memberRef, translatedFunction)
|
||||
}
|
||||
|
||||
// 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() {
|
||||
|
||||
+2
@@ -208,6 +208,8 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene
|
||||
val argument = expression.getValueArgument(index)
|
||||
val result = argument?.accept(transformer, context)
|
||||
if (result == null) {
|
||||
if (context.staticContext.backendContext.es6mode) return@mapTo JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(2))
|
||||
|
||||
assert(expression is IrFunctionAccessExpression && expression.symbol.owner.isExternalOrInheritedFromExternal())
|
||||
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||
} else
|
||||
|
||||
Reference in New Issue
Block a user