diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 5b964d4762e..1c275d872d1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -104,6 +104,13 @@ class JsIntrinsics( val jsToLong = getInternalFunction("toLong") + // RTTI: + + val isInterfaceSymbol = getInternalFunction("isInterface") + val isArraySymbol = getInternalFunction("isArray") + // val isCharSymbol = getInternalFunction("isChar") + val isObjectSymbol = getInternalFunction("isObject") + // Other: val jsObjectCreate = defineObjectCreateIntrinsic() // Object.create 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 c1ba8855c10..9bc10560112 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 @@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.ir.backend.js.lower.* import org.jetbrains.kotlin.ir.backend.js.lower.inline.* import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer @@ -21,14 +23,25 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator +import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor +import org.jetbrains.kotlin.serialization.js.ModuleKind + +data class Result(val moduleDescriptor: ModuleDescriptor, val generatedCode: String) fun compile( project: Project, files: List, configuration: CompilerConfiguration, - export: FqName -): String { - val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, emptyList(), emptyList()) + export: FqName? = null, + dependencies: List = listOf() +): Result { + val moduleDescriptors = + dependencies + .filterIsInstance() + .map { JsModuleDescriptor("", ModuleKind.PLAIN, listOf(), it) } + + val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, moduleDescriptors, emptyList()) + ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) @@ -56,10 +69,10 @@ fun compile( val program = moduleFragment.accept(IrModuleToJsTransformer(context), null) - return program.toString() + return Result(analysisResult.moduleDescriptor, program.toString()) } -fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) { +private fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) { FunctionInlining(this).inline(moduleFragment) moduleFragment.referenceAllTypeExternalClassifiers(symbolTable) @@ -77,7 +90,7 @@ fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) { } } -fun JsIrBackendContext.lower(file: IrFile) { +private fun JsIrBackendContext.lower(file: IrFile) { LateinitLowering(this, true).lower(file) DefaultArgumentStubGenerator(this).runOnFilePostfix(file) DefaultParameterInjector(this).runOnFilePostfix(file) @@ -110,4 +123,4 @@ private fun IrModuleFragment.removeDuplicates(): IrModuleFragment { dependencyModules.forEach { it.externalPackageFragments.removeDuplicates() } return this -} \ No newline at end of file +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index 5cbdf1cff94..e81ce016d43 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -43,10 +43,10 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass { private val eqeq = context.irBuiltIns.eqeqSymbol - private val isInterfaceSymbol = getInternalFunction("isInterface") - private val isArraySymbol = getInternalFunction("isArray") -// private val isCharSymbol = getInternalFunction("isChar") - private val isObjectSymbol = getInternalFunction("isObject") + private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol + private val isArraySymbol get() = context.intrinsics.isArraySymbol +// private val isCharSymbol get() = context.intrinsics.isCharSymbol + private val isObjectSymbol get() = context.intrinsics.isObjectSymbol private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol private val typeOfIntrinsicSymbol = context.intrinsics.jsTypeOf.symbol @@ -60,8 +60,6 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass { private val litTrue: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true) private val litNull: IrExpression = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType) - private fun getInternalFunction(name: String) = context.symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single()) - override fun lower(irFile: IrFile) { // TODO: get rid of descriptors irFile.transformChildren(object : IrElementTransformer { diff --git a/compiler/testData/codegen/box/delegation/hiddenSuperOverrideIn1.0.kt b/compiler/testData/codegen/box/delegation/hiddenSuperOverrideIn1.0.kt index baa28b94765..390d1773e91 100644 --- a/compiler/testData/codegen/box/delegation/hiddenSuperOverrideIn1.0.kt +++ b/compiler/testData/codegen/box/delegation/hiddenSuperOverrideIn1.0.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JVM_IR // LANGUAGE_VERSION: 1.0 diff --git a/compiler/testData/codegen/box/ieee754/nullableDoubleEquals10.kt b/compiler/testData/codegen/box/ieee754/nullableDoubleEquals10.kt index 2e7e0ca5d1f..aec2421eaa9 100644 --- a/compiler/testData/codegen/box/ieee754/nullableDoubleEquals10.kt +++ b/compiler/testData/codegen/box/ieee754/nullableDoubleEquals10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS_IR fun myEquals(a: Double?, b: Double?) = a == b fun myEquals1(a: Double?, b: Double) = a == b diff --git a/compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals10.kt b/compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals10.kt index 22a5ffae447..7ec29384f5a 100644 --- a/compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals10.kt +++ b/compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS_IR fun myNotEquals(a: Double?, b: Double?) = a != b fun myNotEquals1(a: Double?, b: Double) = a != b diff --git a/compiler/testData/codegen/box/ieee754/nullableFloatEquals10.kt b/compiler/testData/codegen/box/ieee754/nullableFloatEquals10.kt index 90fa7837087..b6899058120 100644 --- a/compiler/testData/codegen/box/ieee754/nullableFloatEquals10.kt +++ b/compiler/testData/codegen/box/ieee754/nullableFloatEquals10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS_IR fun myEquals(a: Float?, b: Float?) = a == b fun myEquals1(a: Float?, b: Float) = a == b diff --git a/compiler/testData/codegen/box/ieee754/nullableFloatNotEquals10.kt b/compiler/testData/codegen/box/ieee754/nullableFloatNotEquals10.kt index 26904b12809..a9eeb821db4 100644 --- a/compiler/testData/codegen/box/ieee754/nullableFloatNotEquals10.kt +++ b/compiler/testData/codegen/box/ieee754/nullableFloatNotEquals10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS_IR fun myNotEquals(a: Float?, b: Float?) = a != b fun myNotEquals1(a: Float?, b: Float) = a != b diff --git a/compiler/testData/codegen/box/ieee754/whenNullableSmartCast10.kt b/compiler/testData/codegen/box/ieee754/whenNullableSmartCast10.kt index 6b3bab80b66..f497a7468b6 100644 --- a/compiler/testData/codegen/box/ieee754/whenNullableSmartCast10.kt +++ b/compiler/testData/codegen/box/ieee754/whenNullableSmartCast10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS_IR fun box(): String { val nullValue: Any? = null val nullDouble: Double? = null diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt index 139fb07c023..8f18fb074d6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt @@ -131,8 +131,7 @@ abstract class BasicBoxTest( val mainModuleName = if (TEST_MODULE in modules) TEST_MODULE else DEFAULT_MODULE val mainModule = modules[mainModuleName] ?: error("No module with name \"$mainModuleName\"") - val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension( - TEST_DATA_DIR_PATH + COMMON_FILES_DIR, JavaScript.EXTENSION) + val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, JavaScript.EXTENSION) val localCommonFile = file.parent + "/" + COMMON_FILES_NAME + JavaScript.DOT_EXTENSION val localCommonFiles = if (File(localCommonFile).exists()) listOf(localCommonFile) else emptyList() @@ -305,10 +304,10 @@ abstract class BasicBoxTest( ) { val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") } val testFiles = kotlinFiles.map { it.fileName } - val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension( - TEST_DATA_DIR_PATH + COMMON_FILES_DIR, KotlinFileType.EXTENSION) + val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, KotlinFileType.EXTENSION) val localCommonFile = directory + "/" + COMMON_FILES_NAME + "." + KotlinFileType.EXTENSION val localCommonFiles = if (File(localCommonFile).exists()) listOf(localCommonFile) else emptyList() + // TODO probably it's no longer needed. val additionalCommonFiles = additionalCommonFileDirectories.flatMap { baseDir -> JsTestUtils.getFilesInDirectoryByExtension(baseDir + "/", KotlinFileType.EXTENSION) } @@ -750,9 +749,11 @@ abstract class BasicBoxTest( const val TEST_DATA_DIR_PATH = "js/js.translator/testData/" const val DIST_DIR_JS_PATH = "dist/js/" - private val COMMON_FILES_NAME = "_common" - private val COMMON_FILES_DIR = "_commonFiles/" - private val MODULE_EMULATION_FILE = TEST_DATA_DIR_PATH + "/moduleEmulation.js" + private const val COMMON_FILES_NAME = "_common" + private const val COMMON_FILES_DIR = "_commonFiles/" + const val COMMON_FILES_DIR_PATH = TEST_DATA_DIR_PATH + COMMON_FILES_DIR + + private const val MODULE_EMULATION_FILE = TEST_DATA_DIR_PATH + "/moduleEmulation.js" private val MODULE_KIND_PATTERN = Pattern.compile("^// *MODULE_KIND: *(.+)$", Pattern.MULTILINE) private val NO_MODULE_SYSTEM_PATTERN = Pattern.compile("^// *NO_JS_MODULE_SYSTEM", Pattern.MULTILINE) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt index 5078927c8a5..6cd958e9b4b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt @@ -5,6 +5,11 @@ package org.jetbrains.kotlin.js.test +import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.ir.backend.js.Result import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.js.config.JsConfig import org.jetbrains.kotlin.js.facade.MainCallParameters @@ -17,9 +22,13 @@ private val runtimeSources = listOfKtFilesFrom( "libraries/stdlib/js/src/kotlin/core.kt", "core/builtins/native/kotlin/Number.kt", "core/builtins/native/kotlin/Comparable.kt", - "libraries/stdlib/js/irRuntime" + "libraries/stdlib/js/irRuntime", + BasicBoxTest.COMMON_FILES_DIR_PATH ) +private var runtimeResult: Result? = null +private val runtimeFile = File("js/js.translator/testData/out/irBox/testRuntime.js") + abstract class BasicIrBoxTest( pathToTestDir: String, testGroupOutputDirPrefix: String, @@ -50,27 +59,29 @@ abstract class BasicIrBoxTest( testPackage: String?, testFunction: String ) { - val runtime = runtimeSources.map { createPsiFile(it) } - - val filesToIgnore = listOf( - // TODO: temporary ignore some files from _commonFiles directory since they can't be compiled correctly by JS IR BE yet. - // Also, some declarations depends on stdlib but we don't have any library support in JS IR BE yet - // and probably it will be better to avoid using stdlib in testData as much as possible. - "js/js.translator/testData/_commonFiles/arrayAsserts.kt" - ) - val filesToCompile = units .map { (it as TranslationUnit.SourceFile).file } - .filter { file -> filesToIgnore.none { file.virtualFilePath.endsWith(it) } } + // TODO: split input files to some parts (global common, local common, test) + .filterNot { it.virtualFilePath.contains(BasicBoxTest.COMMON_FILES_DIR_PATH) } - val code = compile( + if (runtimeResult == null) { + val myConfiguration = config.configuration.copy() + + // TODO: is it right in general? Maybe sometimes we need to compile with newer versions or with additional language features. + myConfiguration.languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE) + + runtimeResult = compile(config.project, runtimeSources.map(::createPsiFile), myConfiguration) + runtimeFile.write(runtimeResult!!.generatedCode) + } + + val result = compile( config.project, - runtime + filesToCompile, + filesToCompile, config.configuration, - FqName((testPackage?.let { "$it." } ?: "") + testFunction)) + FqName((testPackage?.let { "$it." } ?: "") + testFunction), + listOf(runtimeResult!!.moduleDescriptor)) - outputFile.parentFile.mkdirs() - outputFile.writeText(code) + outputFile.write(result.generatedCode) } override fun runGeneratedCode( @@ -82,7 +93,9 @@ abstract class BasicIrBoxTest( withModuleSystem: Boolean ) { // TODO: should we do anything special for module systems? - super.runGeneratedCode(jsFiles, null, null, testFunction, expectedResult, false) + // TODO: return list of js from translateFiles and provide then to this function with other js files + // TODO: cache runtime.js and don't cache kotlin.js for IR BE tests + super.runGeneratedCode(listOf(runtimeFile.path) + jsFiles, null, null, testFunction, expectedResult, false) } } @@ -95,4 +108,9 @@ private fun listOfKtFilesFrom(vararg paths: String): List { .map { it.relativeToOrSelf(currentDir).path } .asIterable() } -} \ No newline at end of file +} + +private fun File.write(text: String) { + parentFile.mkdirs() + writeText(text) +} diff --git a/js/js.translator/testData/_commonFiles/arrayAsserts.kt b/js/js.translator/testData/_commonFiles/arrayAsserts.kt index 36519db290f..dcd1b78faf6 100644 --- a/js/js.translator/testData/_commonFiles/arrayAsserts.kt +++ b/js/js.translator/testData/_commonFiles/arrayAsserts.kt @@ -10,7 +10,7 @@ fun assertArrayEquals(expected: Array, actual: Array, message: private fun arraysEqual(first: Array, second: Array): Boolean { if (first === second) return true if (first.size != second.size) return false - for (index in first.indices) { + for (index in 0..first.size - 1) { if (!equal(first[index], second[index])) return false } return true