JS IR: per-module .js generation support

This commit is contained in:
Anton Bannykh
2020-06-03 18:41:52 +03:00
parent deb5dc1057
commit da79f93c61
38 changed files with 1358 additions and 124 deletions
@@ -16,8 +16,17 @@
package org.jetbrains.kotlin.js.backend.ast
class JsImportedModule(val externalName: String, var internalName: JsName, val plainReference: JsExpression?) {
class JsImportedModule @JvmOverloads constructor(
val externalName: String,
var internalName: JsName,
val plainReference: JsExpression?,
val relativeRequirePath: Boolean = false
) {
val key = JsImportedModuleKey(externalName, plainReference?.toString())
}
val JsImportedModule.requireName: String
get() = if (relativeRequirePath) "./$externalName.js" else externalName
data class JsImportedModuleKey(val baseName: String, val plainName: String?)
@@ -129,6 +129,7 @@ abstract class BasicBoxTest(
val expectActualLinker = EXPECT_ACTUAL_LINKER.matcher(fileContent).find()
val skipDceDriven = SKIP_DCE_DRIVEN.matcher(fileContent).find()
val splitPerModule = SPLIT_PER_MODULE.matcher(fileContent).find()
TestFileFactoryImpl(coroutinesPackage).use { testFactory ->
val inputFiles = TestFiles.createTestFiles(
@@ -173,7 +174,7 @@ abstract class BasicBoxTest(
testFactory.tmpDir,
file.parent, module, outputFileName, dceOutputFileName, pirOutputFileName, dependencies, allDependencies, friends, modules.size > 1,
!SKIP_SOURCEMAP_REMAPPING.matcher(fileContent).find(), outputPrefixFile, outputPostfixFile,
actualMainCallParameters, testPackage, testFunction, needsFullIrRuntime, isMainModule, expectActualLinker, skipDceDriven
actualMainCallParameters, testPackage, testFunction, needsFullIrRuntime, isMainModule, expectActualLinker, skipDceDriven, splitPerModule
)
when {
@@ -395,7 +396,8 @@ abstract class BasicBoxTest(
needsFullIrRuntime: Boolean,
isMainModule: Boolean,
expectActualLinker: Boolean,
skipDceDriven: Boolean
skipDceDriven: Boolean,
splitPerModule: Boolean
) {
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
val testFiles = kotlinFiles.map { it.fileName }
@@ -419,7 +421,7 @@ abstract class BasicBoxTest(
val incrementalData = IncrementalData()
translateFiles(
psiFiles.map(TranslationUnit::SourceFile), outputFile, dceOutputFile, pirOutputFile, config, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, isMainModule, skipDceDriven
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, isMainModule, skipDceDriven, splitPerModule
)
if (incrementalCompilationChecksEnabled && module.hasFilesToRecompile) {
@@ -471,7 +473,7 @@ abstract class BasicBoxTest(
translateFiles(
translationUnits, recompiledOutputFile, recompiledOutputFile, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, false, true
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, false, true, false
)
val originalOutput = FileUtil.loadFile(outputFile)
@@ -544,7 +546,8 @@ abstract class BasicBoxTest(
testFunction: String,
needsFullIrRuntime: Boolean,
isMainModule: Boolean,
skipDceDriven: Boolean
skipDceDriven: Boolean,
splitPerModule: Boolean
) {
val translator = K2JSTranslator(config, false)
val translationResult = translator.translateUnits(ExceptionThrowingReporter, units, mainCallParameters)
@@ -929,6 +932,7 @@ abstract class BasicBoxTest(
private val KJS_WITH_FULL_RUNTIME = Pattern.compile("^// *KJS_WITH_FULL_RUNTIME *\$", Pattern.MULTILINE)
private val EXPECT_ACTUAL_LINKER = Pattern.compile("^// EXPECT_ACTUAL_LINKER *$", Pattern.MULTILINE)
private val SKIP_DCE_DRIVEN = Pattern.compile("^// *SKIP_DCE_DRIVEN *$", Pattern.MULTILINE)
private val SPLIT_PER_MODULE = Pattern.compile("^// *SPLIT_PER_MODULE *$", Pattern.MULTILINE)
@JvmStatic
protected val runTestInNashorn = getBoolean("kotlin.js.useNashorn")
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.parsing.parseBoolean
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
import java.io.File
@@ -56,6 +57,8 @@ abstract class BasicIrBoxTest(
val runEs6Mode: Boolean = getBoolean("kotlin.js.ir.es6", false)
val perModule: Boolean = getBoolean("kotlin.js.ir.perModule")
private val osName: String = System.getProperty("os.name").toLowerCase()
// TODO Design incremental compilation for IR and add test support
@@ -63,8 +66,11 @@ abstract class BasicIrBoxTest(
private val compilationCache = mutableMapOf<String, String>()
private val cachedDependencies = mutableMapOf<String, Collection<String>>()
override fun doTest(filePath: String, expectedResult: String, mainCallParameters: MainCallParameters, coroutinesPackage: String) {
compilationCache.clear()
cachedDependencies.clear()
super.doTest(filePath, expectedResult, mainCallParameters, coroutinesPackage)
}
@@ -86,7 +92,8 @@ abstract class BasicIrBoxTest(
testFunction: String,
needsFullIrRuntime: Boolean,
isMainModule: Boolean,
skipDceDriven: Boolean
skipDceDriven: Boolean,
splitPerModule: Boolean
) {
val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file }
@@ -135,18 +142,13 @@ abstract class BasicIrBoxTest(
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
generateFullJs = true,
generateDceJs = runIrDce,
es6mode = runEs6Mode
es6mode = runEs6Mode,
multiModule = splitPerModule || perModule
)
val wrappedCode =
wrapWithModuleEmulationMarkers(compiledModule.jsCode!!, moduleId = config.moduleId, moduleKind = config.moduleKind)
outputFile.write(wrappedCode)
compiledModule.jsCode!!.writeTo(outputFile, config)
compiledModule.dceJsCode?.let { dceJsCode ->
val dceWrappedCode =
wrapWithModuleEmulationMarkers(dceJsCode, moduleId = config.moduleId, moduleKind = config.moduleKind)
dceOutputFile.write(dceWrappedCode)
}
compiledModule.dceJsCode?.writeTo(dceOutputFile, config)
if (generateDts) {
val dtsFile = outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")
@@ -166,11 +168,9 @@ abstract class BasicIrBoxTest(
mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null },
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction))),
dceDriven = true,
es6mode = runEs6Mode
).jsCode!!.let { pirCode ->
val pirWrappedCode = wrapWithModuleEmulationMarkers(pirCode, moduleId = config.moduleId, moduleKind = config.moduleKind)
pirOutputFile.write(pirWrappedCode)
}
es6mode = runEs6Mode,
multiModule = splitPerModule || perModule
).jsCode!!.writeTo(pirOutputFile, config)
}
} else {
generateKLib(
@@ -188,6 +188,23 @@ abstract class BasicIrBoxTest(
}
}
private fun JsCode.writeTo(outputFile: File, config: JsConfig) {
val wrappedCode =
wrapWithModuleEmulationMarkers(mainModule, moduleId = config.moduleId, moduleKind = config.moduleKind)
outputFile.write(wrappedCode)
val dependencyPaths = mutableListOf<String>()
dependencies.forEach { (moduleId, code) ->
val wrappedCode = wrapWithModuleEmulationMarkers(code, config.moduleKind, moduleId)
val dependencyPath = outputFile.absolutePath.replace("_v5.js", "-${moduleId}_v5.js")
dependencyPaths += dependencyPath
File(dependencyPath).write(wrappedCode)
}
cachedDependencies[outputFile.absolutePath] = dependencyPaths
}
override fun dontRunOnSpecificPlatform(targetBackend: TargetBackend): Boolean {
if (targetBackend != TargetBackend.JS_IR_ES6) return false
if (!runEs6Mode) return false
@@ -210,7 +227,8 @@ abstract class BasicIrBoxTest(
// TODO: should we do anything special for module systems?
// TODO: return list of js from translateFiles and provide then to this function with other js files
testChecker.check(jsFiles, testModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
val allFiles = jsFiles.flatMap { file -> cachedDependencies[file]?.let { deps -> deps + file } ?: listOf(file) }
testChecker.check(allFiles, testModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
}
}
@@ -797,6 +797,104 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
}
}
@TestMetadata("js/js.translator/testData/box/crossModuleRefIR")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CrossModuleRefIR extends AbstractIrBoxJsES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInCrossModuleRefIR() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/crossModuleRefIR"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@TestMetadata("callableObjectRef.kt")
public void testCallableObjectRef() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/callableObjectRef.kt");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/constructor.kt");
}
@TestMetadata("export.kt")
public void testExport() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/export.kt");
}
@TestMetadata("inheritance.kt")
public void testInheritance() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inheritance.kt");
}
@TestMetadata("inlineJsModule.kt")
public void testInlineJsModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModule.kt");
}
@TestMetadata("inlineJsModuleNonIdentifier.kt")
public void testInlineJsModuleNonIdentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModuleNonIdentifier.kt");
}
@TestMetadata("inlineJsModulePackage.kt")
public void testInlineJsModulePackage() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModulePackage.kt");
}
@TestMetadata("inlineModule.kt")
public void testInlineModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModule.kt");
}
@TestMetadata("inlineModuleNonIndentifier.kt")
public void testInlineModuleNonIndentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModuleNonIndentifier.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/lambda.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/object.kt");
}
@TestMetadata("objectInInlineClosure.kt")
public void testObjectInInlineClosure() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectInInlineClosure.kt");
}
@TestMetadata("objectIsObject.kt")
public void testObjectIsObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectIsObject.kt");
}
@TestMetadata("topLevelExtension.kt")
public void testTopLevelExtension() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelExtension.kt");
}
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelFunction.kt");
}
@TestMetadata("topLevelMutableProperty.kt")
public void testTopLevelMutableProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelMutableProperty.kt");
}
@TestMetadata("topLevelProperty.kt")
public void testTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelProperty.kt");
}
}
@TestMetadata("js/js.translator/testData/box/dataClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -797,6 +797,104 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
}
}
@TestMetadata("js/js.translator/testData/box/crossModuleRefIR")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CrossModuleRefIR extends AbstractIrBoxJsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInCrossModuleRefIR() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/crossModuleRefIR"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("callableObjectRef.kt")
public void testCallableObjectRef() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/callableObjectRef.kt");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/constructor.kt");
}
@TestMetadata("export.kt")
public void testExport() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/export.kt");
}
@TestMetadata("inheritance.kt")
public void testInheritance() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inheritance.kt");
}
@TestMetadata("inlineJsModule.kt")
public void testInlineJsModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModule.kt");
}
@TestMetadata("inlineJsModuleNonIdentifier.kt")
public void testInlineJsModuleNonIdentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModuleNonIdentifier.kt");
}
@TestMetadata("inlineJsModulePackage.kt")
public void testInlineJsModulePackage() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModulePackage.kt");
}
@TestMetadata("inlineModule.kt")
public void testInlineModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModule.kt");
}
@TestMetadata("inlineModuleNonIndentifier.kt")
public void testInlineModuleNonIndentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModuleNonIndentifier.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/lambda.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/object.kt");
}
@TestMetadata("objectInInlineClosure.kt")
public void testObjectInInlineClosure() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectInInlineClosure.kt");
}
@TestMetadata("objectIsObject.kt")
public void testObjectIsObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectIsObject.kt");
}
@TestMetadata("topLevelExtension.kt")
public void testTopLevelExtension() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelExtension.kt");
}
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelFunction.kt");
}
@TestMetadata("topLevelMutableProperty.kt")
public void testTopLevelMutableProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelMutableProperty.kt");
}
@TestMetadata("topLevelProperty.kt")
public void testTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelProperty.kt");
}
}
@TestMetadata("js/js.translator/testData/box/dataClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -797,6 +797,104 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
}
}
@TestMetadata("js/js.translator/testData/box/crossModuleRefIR")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CrossModuleRefIR extends AbstractBoxJsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInCrossModuleRefIR() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/crossModuleRefIR"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("callableObjectRef.kt")
public void testCallableObjectRef() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/callableObjectRef.kt");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/constructor.kt");
}
@TestMetadata("export.kt")
public void testExport() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/export.kt");
}
@TestMetadata("inheritance.kt")
public void testInheritance() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inheritance.kt");
}
@TestMetadata("inlineJsModule.kt")
public void testInlineJsModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModule.kt");
}
@TestMetadata("inlineJsModuleNonIdentifier.kt")
public void testInlineJsModuleNonIdentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModuleNonIdentifier.kt");
}
@TestMetadata("inlineJsModulePackage.kt")
public void testInlineJsModulePackage() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineJsModulePackage.kt");
}
@TestMetadata("inlineModule.kt")
public void testInlineModule() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModule.kt");
}
@TestMetadata("inlineModuleNonIndentifier.kt")
public void testInlineModuleNonIndentifier() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/inlineModuleNonIndentifier.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/lambda.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/object.kt");
}
@TestMetadata("objectInInlineClosure.kt")
public void testObjectInInlineClosure() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectInInlineClosure.kt");
}
@TestMetadata("objectIsObject.kt")
public void testObjectIsObject() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/objectIsObject.kt");
}
@TestMetadata("topLevelExtension.kt")
public void testTopLevelExtension() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelExtension.kt");
}
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelFunction.kt");
}
@TestMetadata("topLevelMutableProperty.kt")
public void testTopLevelMutableProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelMutableProperty.kt");
}
@TestMetadata("topLevelProperty.kt")
public void testTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/crossModuleRefIR/topLevelProperty.kt");
}
}
@TestMetadata("js/js.translator/testData/box/dataClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -0,0 +1,27 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1289
// MODULE: lib
// FILE: lib.kt
package lib
object O {
operator fun invoke() = "OK"
}
inline fun callO() = O()
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box(): String {
val a = O()
if (a != "OK") return "fail: simple: $a"
val b = callO()
if (b != "OK") return "fail: inline: $a"
return "OK"
}
@@ -0,0 +1,72 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1291
// MODULE: lib
// FILE: lib.kt
package lib
class A(val x: Int) {
constructor(a: Int, b: Int) : this(a + b)
}
external class B(x: Int) {
constructor(a: Int, b: Int)
val x: Int
}
// TODO: may be useful after implementing local classes in inline functions
/*
inline fun foo(p: Int, q: Int, r: Int): Pair<Int, Int> {
class C(val x : Int) {
constructor(a: Int, b: Int) : this(a + b)
}
return Pair(C(p).x, C(q, r).x)
}
*/
inline fun callPrimaryConstructor(x: Int) = A(x).x
inline fun callSecondaryConstructor(x: Int, y: Int) = A(x, y).x
// FILE: lib.js
function B(x, y) {
this.x = x;
if (typeof y !== 'undefined') {
this.x += y;
}
}
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box(): String {
val a = A(23).x
if (a != 23) return "fail: primary constructor: $a"
val b = A(40, 2).x
if (b != 42) return "fail: secondary constructor: $b"
val c = B(99).x
if (c != 99) return "fail: native primary constructor: $c"
val d = B(100, 11).x
if (d != 111) return "fail: native secondary constructor: $d"
/*
val (e, f) = foo(123, 320, 1)
if (e != 123) return "fail: local primary constructor: $e"
if (f != 321) return "fail: local secondary constructor: $f"
*/
val g = callPrimaryConstructor(55)
if (g != 55) return "fail: primary constructor from inline function: $g"
val h = callSecondaryConstructor(990, 9)
if (h != 999) return "fail: secondary constructor from inline function: $h"
return "OK"
}
@@ -0,0 +1,32 @@
// IGNORE_BACKEND: JS
// SPLIT_PER_MODULE
// RUN_PLAIN_BOX_FUNCTION
// EXPECTED_REACHABLE_NODES: 1316
// MODULE: lib1
// FILE: lib1.kt
@JsExport
fun O(): String = "O"
// MODULE: lib2(lib1)
// FILE: lib2.kt
@JsExport
fun K(): String = "K"
// MODULE: main(lib1, lib2)
// FILE: main.kt
@JsExport
fun test() = O() + K()
// FILE: test.js
function box() {
if (main.test() != "OK") return "fail 1";
return kotlin_lib1.O() + kotlin_lib2.K();
}
@@ -0,0 +1,27 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1292
// MODULE: lib
// FILE: lib.kt
package lib
open class A {
fun foo() = 23
}
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.A
class B : A() {
fun bar() = foo() + 1
}
fun box(): String {
val result = B().bar()
if (result != 24) return "fail: $result"
return "OK"
}
@@ -0,0 +1,26 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1316
// MODULE: lib1
// FILE: lib1.js
define("lib1", [], function() {
return function() {
return "OK";
}
})
// MODULE: lib2(lib1)
// FILE: lib2.kt
// MODULE_KIND: AMD
@JsModule("lib1")
external fun foo(): String
// MODULE: lib3(lib2)
// FILE: lib3.kt
// MODULE_KIND: AMD
inline fun bar() = foo()
// MODULE: main(lib3)
// FILE: main.kt
// MODULE_KIND: AMD
fun box() = bar()
@@ -0,0 +1,26 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1316
// MODULE: lib-1
// FILE: lib-1.js
define("lib-1", [], function() {
return function() {
return "OK";
}
})
// MODULE: lib2(lib-1)
// FILE: lib2.kt
// MODULE_KIND: AMD
@JsModule("lib-1")
external fun foo(): String
// MODULE: lib3(lib2)
// FILE: lib3.kt
// MODULE_KIND: AMD
inline fun bar() = foo()
// MODULE: main(lib3)
// FILE: main.kt
// MODULE_KIND: AMD
fun box() = bar()
@@ -0,0 +1,29 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: lib1
// FILE: lib1.js
define("lib1", [], function() {
return {
foo: function() {
return "OK";
}
};
})
// MODULE: lib2(lib1)
// FILE: lib2.kt
// MODULE_KIND: AMD
@file:JsModule("lib1")
external fun foo(): String
// MODULE: lib3(lib2)
// FILE: lib3.kt
// MODULE_KIND: AMD
inline fun bar() = foo()
// MODULE: main(lib3)
// FILE: main.kt
// MODULE_KIND: AMD
fun box() = bar()
@@ -0,0 +1,16 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1283
// MODULE: lib1
// FILE: lib1.kt
fun foo() = "OK"
// MODULE: lib2(lib1)
// FILE: lib2.kt
inline fun bar() = foo()
// MODULE: main(lib1, lib2)
// FILE: main.kt
fun box() = bar()
@@ -0,0 +1,16 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1283
// MODULE: 1
// FILE: lib1.kt
fun foo() = "OK"
// MODULE: 2(1)
// FILE: lib2.kt
inline fun bar() = foo()
// MODULE: main(2)
// FILE: main.kt
fun box() = bar()
@@ -0,0 +1,19 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1283
// MODULE: lib
// FILE: lib.kt
package lib
fun bar(f: () -> String) = f()
inline fun foo(): String {
return bar { "OK" }
}
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box() = foo()
@@ -0,0 +1,37 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1289
// MODULE: lib
// FILE: lib.kt
package lib
var log = ""
object O {
init {
log += "O.init;"
}
fun result() = "OK"
}
fun getResult(): String {
log += "before;"
val result = O.result()
log += "after;"
return result
}
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box(): String {
val result = getResult()
if (result != "OK") return "fail: unexpected result: $result"
if (log != "before;O.init;after;") return "fail: wrong evaluation order: $log"
return "OK"
}
@@ -0,0 +1,27 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1382
// MODULE: lib
// FILE: lib.kt
package lib
object O {
val result = "OK"
inline fun foo(): String {
val o = object {
fun bar() = O
}
return fetch(o.bar())
}
}
fun fetch(o: O) = o.result
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box() = O.foo()
@@ -0,0 +1,21 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: lib
// FILE: lib.kt
package lib
object O
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box(): String {
var o: Any = O
if (o !is O) return "fail1"
if (!(o is O)) return "fail2"
return "OK"
}
@@ -0,0 +1,44 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1290
// MODULE: lib
// FILE: lib.kt
package lib
class A(val x: Int)
fun A.foo() = 23 + x
inline fun A.baz() = 99 + x
inline fun A.callFoo() = foo()
inline fun A.buzz(): Int {
val o = object {
fun f() = 111 + x
}
return o.f()
}
// MODULE: main(lib)
// FILE: main.kt
package main
import lib.*
fun box(): String {
val a = A(1).foo()
if (a != 24) return "fail: simple function: $a"
val c = A(1).baz()
if (c != 100) return "fail: inline function: $c"
val d = A(1).buzz()
if (d != 112) return "fail: inline function with object expression: $d"
val e = A(2).callFoo()
if (e != 25) return "fail: inline function calling another function: $e"
return "OK"
}
@@ -0,0 +1,51 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1287
// MODULE: lib
// FILE: lib.kt
package lib
fun foo() = 23
external fun bar(): Int = definedExternally
inline fun baz() = 99
inline fun callFoo() = foo()
inline fun buzz(): Int {
val o = object {
fun f() = 111
}
return o.f()
}
// FILE: lib.js
function bar() {
return 42;
}
// MODULE: main(lib)
// FILE: main.kt
package main
fun box(): String {
val a = lib.foo()
if (a != 23) return "fail: simple function: $a"
val b = lib.bar()
if (b != 42) return "fail: native function: $b"
val c = lib.baz()
if (c != 99) return "fail: inline function: $c"
val d = lib.buzz()
if (d != 111) return "fail: inline function with object expression: $d"
val e = lib.callFoo()
if (e != 23) return "fail: inline function calling another function: $e"
return "OK"
}
@@ -0,0 +1,38 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1286
// MODULE: lib
// FILE: lib.kt
package lib
var foo = 23
var bar: Int = 42
get() = field
set(value) {
field = value
}
@JsName("faz") var baz = 99
// MODULE: main(lib)
// FILE: lib.kt
package main
import lib.*
fun box(): String {
if (foo != 23) return "fail: simple property initial value: $foo"
foo = 24
if (foo != 24) return "fail: simple property new value: $foo"
if (bar != 42) return "fail: property with accessor initial value: $bar"
bar = 43
if (bar != 43) return "fail: property with accessor new value: $bar"
if (baz != 99) return "fail: renamed property initial value: $baz"
baz = 100
if (baz != 100) return "fail: renamed property new value: $baz"
return "OK"
}
@@ -0,0 +1,48 @@
// SPLIT_PER_MODULE
// EXPECTED_REACHABLE_NODES: 1287
// MODULE: lib
// FILE: lib.kt
package lib
val foo = 23
val boo: Int
get() = 42
external val bar: Int = definedExternally
external val far: Int
get() = definedExternally
// TODO: annotations like this are not serialized properly. Uncomment after KT-14529 gets fixed
/*
val fuzz: Int
@JsName("getBuzz") get() = 55
*/
inline fun fetchFoo() = foo
@JsName("fee")
val tee = 2525
// FILE: lib.js
var bar = 99
var far = 111
// MODULE: main(lib)
// FILE: lib.kt
package main
import lib.*
fun box(): String {
if (foo != 23) return "fail: simple property: $foo"
if (boo != 42) return "fail: property with accessor: $boo"
if (bar != 99) return "fail: native property: $bar"
if (far != 111) return "fail: native property with accessor: $far"
//if (fuzz != 55) return "fail: property with JsName on accessor: $fuzz"
if (tee != 2525) return "fail: native property with JsName: $tee"
return "OK"
}