diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index ef0548196bd..3db13aaf700 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -33,11 +33,6 @@ fun compile( export: FqName? = null, dependencies: List = 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()) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt index d68813f6590..56245a3c34f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt @@ -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 { @@ -25,12 +26,13 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer { 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): List { - - val statements = mutableListOf() - val visited = mutableSetOf() - - for (name in classModels.keys) { - addPostDeclaration(name, visited, statements, classModels) - } - - return statements - } - - private fun addPostDeclaration( - name: JsName, - visited: MutableSet, - statements: MutableList, - classModels: Map + private fun processClassModels( + classModelMap: Map, + 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() { + 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() + classModelMap[it]?.run { + if (superName != null) neighbors += superName!! + neighbors += interfaces + } + neighbors + }, declarationHandler) } } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 7a99827b1e4..2d489dbd261 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -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() } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsStaticContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsStaticContext.kt index 36710dc25eb..c5c144649a1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsStaticContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsStaticContext.kt @@ -25,6 +25,8 @@ class JsStaticContext( // TODO: use IrSymbol instead of JsName val classModels = mutableMapOf() + val initializerBlock = JsGlobalBlock() + fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context) fun getNameForLoop(loop: IrLoop, context: JsGenerationContext) = nameGenerator.getNameForLoop(loop, context) } \ No newline at end of file diff --git a/compiler/testData/codegen/box/callableReference/property/delegated.kt b/compiler/testData/codegen/box/callableReference/property/delegated.kt index 606aeb70bf9..5a0c6e29e14 100644 --- a/compiler/testData/codegen/box/callableReference/property/delegated.kt +++ b/compiler/testData/codegen/box/callableReference/property/delegated.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR import kotlin.reflect.KProperty val four: Int by NumberDecrypter diff --git a/compiler/testData/codegen/box/callableReference/property/delegatedMutable.kt b/compiler/testData/codegen/box/callableReference/property/delegatedMutable.kt index 00c95aa890f..380f74cd24b 100644 --- a/compiler/testData/codegen/box/callableReference/property/delegatedMutable.kt +++ b/compiler/testData/codegen/box/callableReference/property/delegatedMutable.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR import kotlin.reflect.KProperty var result: String by Delegate diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClassModel.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClassModel.kt index 0a4df27a1cd..88816fd11df 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClassModel.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClassModel.kt @@ -18,5 +18,6 @@ package org.jetbrains.kotlin.js.backend.ast class JsClassModel(val name: JsName, val superName: JsName?) { val interfaces: MutableSet = mutableSetOf() + val preDeclarationBlock = JsGlobalBlock() val postDeclarationBlock = JsGlobalBlock() } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 0dccde657ac..495154033dc 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index 4b3a416664e..c515832abd4 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -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"); diff --git a/js/js.translator/testData/box/inheritance/prototypeOrder.kt b/js/js.translator/testData/box/inheritance/prototypeOrder.kt new file mode 100644 index 00000000000..b04ec7c2367 --- /dev/null +++ b/js/js.translator/testData/box/inheritance/prototypeOrder.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" +} \ No newline at end of file