Fix initialization order
* put inheritance code in the beginning * put top-level initializer after any declaration
This commit is contained in:
committed by
Roman Artemev
parent
cff066f702
commit
0c6256d003
@@ -33,11 +33,6 @@ fun compile(
|
||||
export: FqName? = null,
|
||||
dependencies: List<ModuleDescriptor> = listOf()
|
||||
): Result {
|
||||
// Make compilation stable
|
||||
// Shadow original list to prevent accidental usage
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val files = files.sortedBy { it.virtualFilePath }
|
||||
|
||||
val analysisResult =
|
||||
TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, dependencies.filterIsInstance(), emptyList())
|
||||
|
||||
|
||||
+9
-7
@@ -7,7 +7,8 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsVars
|
||||
|
||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
|
||||
@@ -25,12 +26,13 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
||||
|
||||
override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement {
|
||||
val fieldName = context.getNameForSymbol(declaration.symbol)
|
||||
val initExpression =
|
||||
declaration.initializer?.accept(IrElementToJsExpressionTransformer(), context) ?: JsPrefixOperation(
|
||||
JsUnaryOperator.VOID,
|
||||
JsIntLiteral(1)
|
||||
)
|
||||
return JsVars(JsVars.JsVar(fieldName, initExpression))
|
||||
|
||||
if (declaration.initializer != null) {
|
||||
val initializer = declaration.initializer!!.accept(IrElementToJsExpressionTransformer(), context)
|
||||
context.staticContext.initializerBlock.statements += jsAssignment(fieldName.makeRef(), initializer).makeStmt()
|
||||
}
|
||||
|
||||
return JsVars(JsVars.JsVar(fieldName))
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||
|
||||
+30
-25
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
||||
@@ -27,42 +28,46 @@ class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrEl
|
||||
program.globalBlock.statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
|
||||
program.globalBlock.statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR))
|
||||
|
||||
val preDeclarationBlock = JsGlobalBlock()
|
||||
val postDeclarationBlock = JsGlobalBlock()
|
||||
|
||||
program.globalBlock.statements += preDeclarationBlock
|
||||
|
||||
declaration.files.forEach {
|
||||
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
||||
}
|
||||
|
||||
// sort member forwarding code
|
||||
program.globalBlock.statements += addPostDeclarations(rootContext.staticContext.classModels)
|
||||
processClassModels(rootContext.staticContext.classModels, preDeclarationBlock, postDeclarationBlock)
|
||||
|
||||
program.globalBlock.statements += postDeclarationBlock
|
||||
program.globalBlock.statements += rootContext.staticContext.initializerBlock
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
|
||||
private fun addPostDeclarations(classModels: Map<JsName, JsClassModel>): List<JsStatement> {
|
||||
|
||||
val statements = mutableListOf<JsStatement>()
|
||||
val visited = mutableSetOf<JsName>()
|
||||
|
||||
for (name in classModels.keys) {
|
||||
addPostDeclaration(name, visited, statements, classModels)
|
||||
}
|
||||
|
||||
return statements
|
||||
}
|
||||
|
||||
private fun addPostDeclaration(
|
||||
name: JsName,
|
||||
visited: MutableSet<JsName>,
|
||||
statements: MutableList<JsStatement>,
|
||||
classModels: Map<JsName, JsClassModel>
|
||||
private fun processClassModels(
|
||||
classModelMap: Map<JsName, JsClassModel>,
|
||||
preDeclarationBlock: JsGlobalBlock,
|
||||
postDeclarationBlock: JsGlobalBlock
|
||||
) {
|
||||
if (visited.add(name)) {
|
||||
classModels[name]?.run {
|
||||
superName?.let { addPostDeclaration(it, visited, statements, classModels) }
|
||||
interfaces.forEach { addPostDeclaration(it, visited, statements, classModels) }
|
||||
|
||||
statements += postDeclarationBlock.statements
|
||||
val declarationHandler = object : DFS.AbstractNodeHandler<JsName, Unit>() {
|
||||
override fun result() {}
|
||||
override fun afterChildren(current: JsName) {
|
||||
classModelMap[current]?.let {
|
||||
preDeclarationBlock.statements += it.preDeclarationBlock.statements
|
||||
postDeclarationBlock.statements += it.postDeclarationBlock.statements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DFS.dfs(classModelMap.keys, {
|
||||
val neighbors = mutableListOf<JsName>()
|
||||
classModelMap[it]?.run {
|
||||
if (superName != null) neighbors += superName!!
|
||||
neighbors += interfaces
|
||||
}
|
||||
neighbors
|
||||
}, declarationHandler)
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -43,7 +43,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
when (declaration) {
|
||||
is IrConstructor -> {
|
||||
classBlock.statements += declaration.accept(transformer, context)
|
||||
classBlock.statements += generateInheritanceCode()
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
is IrSimpleFunction -> {
|
||||
generateMemberFunction(declaration)?.let { classBlock.statements += it }
|
||||
@@ -115,6 +115,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
functionBody.statements += JsIf(
|
||||
JsBinaryOperation(JsBinaryOperator.REF_EQ, instanceVar.makeRef(), JsNullLiteral()),
|
||||
// TODO: Fix initialization order
|
||||
jsAssignment(instanceVar.makeRef(), JsNew(classNameRef)).makeStmt()
|
||||
)
|
||||
functionBody.statements += JsReturn(instanceVar.makeRef())
|
||||
@@ -127,7 +128,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val func = JsFunction(JsFunctionScope(context.currentScope, "Ctor for ${irClass.name}"), JsBlock(), "Ctor for ${irClass.name}")
|
||||
func.name = className
|
||||
classBlock.statements += func.makeStmt()
|
||||
classBlock.statements += generateInheritanceCode()
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ class JsStaticContext(
|
||||
// TODO: use IrSymbol instead of JsName
|
||||
val classModels = mutableMapOf<JsName, JsClassModel>()
|
||||
|
||||
val initializerBlock = JsGlobalBlock()
|
||||
|
||||
fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context)
|
||||
fun getNameForLoop(loop: IrLoop, context: JsGenerationContext) = nameGenerator.getNameForLoop(loop, context)
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
val four: Int by NumberDecrypter
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
var result: String by Delegate
|
||||
|
||||
@@ -18,5 +18,6 @@ package org.jetbrains.kotlin.js.backend.ast
|
||||
|
||||
class JsClassModel(val name: JsName, val superName: JsName?) {
|
||||
val interfaces: MutableSet<JsName> = mutableSetOf()
|
||||
val preDeclarationBlock = JsGlobalBlock()
|
||||
val postDeclarationBlock = JsGlobalBlock()
|
||||
}
|
||||
|
||||
+5
@@ -3616,6 +3616,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/inheritance/overrideAnyMethods.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("prototypeOrder.kt")
|
||||
public void testPrototypeOrder() throws Exception {
|
||||
runTest("js/js.translator/testData/box/inheritance/prototypeOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("valOverride.kt")
|
||||
public void testValOverride() throws Exception {
|
||||
runTest("js/js.translator/testData/box/inheritance/valOverride.kt");
|
||||
|
||||
+5
@@ -3616,6 +3616,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/inheritance/overrideAnyMethods.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("prototypeOrder.kt")
|
||||
public void testPrototypeOrder() throws Exception {
|
||||
runTest("js/js.translator/testData/box/inheritance/prototypeOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("valOverride.kt")
|
||||
public void testValOverride() throws Exception {
|
||||
runTest("js/js.translator/testData/box/inheritance/valOverride.kt");
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1117
|
||||
package foo
|
||||
|
||||
class C: B()
|
||||
open class B: A()
|
||||
open class A
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
|
||||
if (c !is A) return "FAIL"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user