From 0a35d841935d5ea69dc0e03cf8159a18d072b7db Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Thu, 1 Dec 2022 22:12:09 +0100 Subject: [PATCH] [JS IR] DTS generation refactoring Keep a DTS fragment in JsIrProgramFragment for each file and build the module DTS from them. --- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 34 ++++---- .../kotlin/ir/backend/js/compiler.kt | 17 +++- .../js/export/ExportModelToTsDeclarations.kt | 27 ++++--- .../ir/backend/js/ic/JsExecutableProducer.kt | 2 +- .../ir/backend/js/ic/JsMultiModuleCache.kt | 2 +- .../irToJs/IrModuleToJsTransformer.kt | 81 ++++++++----------- .../irToJs/JsIrProgramFragment.kt | 3 +- .../serialization/JsIrAstDeserializer.kt | 5 +- .../utils/serialization/JsIrAstSerializer.kt | 2 +- .../js/test/converters/JsIrBackendFacade.kt | 32 ++++---- 10 files changed, 110 insertions(+), 95 deletions(-) diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 045414b3c30..007b32d0bbf 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -119,8 +119,6 @@ class K2JsIrCompiler : CLICompiler() { return K2JSCompilerArguments() } - private data class TransformResult(val out: CompilationOutputs, val dts: String?) - private class Ir2JsTransformer( val arguments: K2JSCompilerArguments, val module: ModulesStructure, @@ -150,18 +148,16 @@ class K2JsIrCompiler : CLICompiler() { ) } - private fun makeJsCodeGeneratorAndDts(): Pair { + private fun makeJsCodeGenerator(): JsCodeGenerator { val ir = lowerIr() val transformer = IrModuleToJsTransformer(ir.context, mainCallArguments, ir.moduleFragmentToUniqueName) val mode = TranslationMode.fromFlags(arguments.irDce, arguments.irPerModule, arguments.irMinimizedMemberNames) - return transformer.makeJsCodeGeneratorAndDts(ir.allModules, mode) + return transformer.makeJsCodeGenerator(ir.allModules, mode) } - fun compileAndTransformIrNew(): TransformResult { - val (generator, dts) = makeJsCodeGeneratorAndDts() - val out = generator.generateJsCode(relativeRequirePath = true, outJsProgram = false) - return TransformResult(out, dts) + fun compileAndTransformIrNew(): CompilationOutputs { + return makeJsCodeGenerator().generateJsCode(relativeRequirePath = true, outJsProgram = false) } } @@ -308,6 +304,8 @@ class K2JsIrCompiler : CLICompiler() { } if (arguments.irProduceJs) { + val moduleKind = configurationJs[JSConfigurationKeys.MODULE_KIND] ?: error("cannot get 'module kind' from configuration") + messageCollector.report(INFO, "Produce executable: $outputDirPath") messageCollector.report(INFO, "Cache directory: ${arguments.cacheDirectory}") @@ -316,14 +314,14 @@ class K2JsIrCompiler : CLICompiler() { val jsExecutableProducer = JsExecutableProducer( mainModuleName = moduleName, - moduleKind = configurationJs[JSConfigurationKeys.MODULE_KIND]!!, + moduleKind = moduleKind, sourceMapsInfo = SourceMapsInfo.from(configurationJs), caches = icCaches, relativeRequirePath = true ) val (outputs, rebuiltModules) = jsExecutableProducer.buildExecutable(arguments.irPerModule, outJsProgram = false) - outputs.write(outputDir, outputName) + outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) messageCollector.report(INFO, "Executable production duration (IC): ${System.currentTimeMillis() - beforeIc2Js}ms") for ((event, duration) in jsExecutableProducer.getStopwatchLaps()) { @@ -390,16 +388,11 @@ class K2JsIrCompiler : CLICompiler() { try { val ir2JsTransformer = Ir2JsTransformer(arguments, module, phaseConfig, messageCollector, mainCallArguments) - val (outputs, tsDefinitions) = ir2JsTransformer.compileAndTransformIrNew() + val outputs = ir2JsTransformer.compileAndTransformIrNew() messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms") - outputs.write(outputDir, outputName) - - if (tsDefinitions != null) { - val dtsFile = outputDir.resolve("$outputName.d.ts") - dtsFile.writeText(tsDefinitions) - } + outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) } catch (e: CompilationException) { messageCollector.report( ERROR, @@ -707,7 +700,7 @@ class K2JsIrCompiler : CLICompiler() { return icCaches } - private fun CompilationOutputs.write(outputDir: File, outputName: String) { + private fun CompilationOutputs.write(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind) { val outputFile = outputDir.resolve("$outputName.js") outputFile.parentFile.mkdirs() outputFile.write(this) @@ -717,6 +710,11 @@ class K2JsIrCompiler : CLICompiler() { it.write(content) } } + + if (genDTS) { + val dtsFile = outputDir.resolve("$outputName.d.ts") + dtsFile.writeText(getFullTsDefinition(moduleName, moduleKind)) + } } private fun File.write(outputs: CompilationOutputs) { 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 695cb340d9f..8f7a9372f16 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 @@ -11,6 +11,8 @@ import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnb import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity +import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment +import org.jetbrains.kotlin.ir.backend.js.export.toTypeScript import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace @@ -24,19 +26,30 @@ import org.jetbrains.kotlin.js.backend.ast.JsProgram import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.RuntimeDiagnostic import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.serialization.js.ModuleKind +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import java.io.File class CompilerResult( val outputs: Map, - val tsDefinitions: String? = null ) class CompilationOutputs( val jsCode: String, + val tsDefinitions: TypeScriptFragment? = null, val jsProgram: JsProgram? = null, val sourceMap: String? = null, val dependencies: Iterable> = emptyList() -) +) { + fun addDependencies(depends: Iterable>): CompilationOutputs { + return CompilationOutputs(jsCode, tsDefinitions, jsProgram, sourceMap, depends) + } + + fun getFullTsDefinition(name: String, moduleKind: ModuleKind): String { + val allTsDefinitions = dependencies.mapNotNull { it.second.tsDefinitions } + listOfNotNull(tsDefinitions) + return allTsDefinitions.toTypeScript(name, moduleKind) + } +} class LoweredIr( val context: JsIrBackendContext, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt index 5c9ca3df117..d10adad6409 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt @@ -25,12 +25,19 @@ private const val declareExorted = "export $declare" private const val NonExistent = "__NonExistent" private const val syntheticObjectNameSeparator = '$' -fun ExportedModule.toTypeScript(): String { - return ExportModelToTsDeclarations().generateTypeScript(name, this) +@JvmInline +value class TypeScriptFragment(val raw: String) + +fun List.toTypeScriptFragment(moduleKind: ModuleKind): TypeScriptFragment { + return ExportModelToTsDeclarations().generateTypeScriptFragment(moduleKind, this) } -fun List.toTypeScript(moduleKind: ModuleKind): String { - return ExportModelToTsDeclarations().generateTypeScript(moduleKind, this) +fun List.joinTypeScriptFragments(): TypeScriptFragment { + return TypeScriptFragment(joinToString("\n") { it.raw }) +} + +fun List.toTypeScript(name: String, moduleKind: ModuleKind): String { + return ExportModelToTsDeclarations().generateTypeScript(name, moduleKind, this) } // TODO: Support module kinds other than plain @@ -40,24 +47,24 @@ class ExportModelToTsDeclarations { private val ModuleKind.indent: String get() = if (this == ModuleKind.PLAIN) " " else "" - fun generateTypeScript(name: String, module: ExportedModule): String { + fun generateTypeScript(name: String, moduleKind: ModuleKind, declarations: List): String { val types = """ type $Nullable = T | null | undefined - """.trimIndent().prependIndent(module.moduleKind.indent) + "\n" + """.trimIndent().prependIndent(moduleKind.indent) + "\n" - val declarationsDts = types + module.declarations.toTypeScript(module.moduleKind) + val declarationsDts = types + declarations.joinTypeScriptFragments().raw val namespaceName = sanitizeName(name, withHash = false) - return when (module.moduleKind) { + return when (moduleKind) { ModuleKind.PLAIN -> "declare namespace $namespaceName {\n$declarationsDts\n}\n" ModuleKind.AMD, ModuleKind.COMMON_JS, ModuleKind.ES -> declarationsDts ModuleKind.UMD -> "$declarationsDts\nexport as namespace $namespaceName;" } } - fun generateTypeScript(moduleKind: ModuleKind, declarations: List): String { - return declarations.toTypeScript(moduleKind) + fun generateTypeScriptFragment(moduleKind: ModuleKind, declarations: List): TypeScriptFragment { + return TypeScriptFragment(declarations.toTypeScript(moduleKind)) } private fun List.toTypeScript(moduleKind: ModuleKind): String { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt index eb75f2dd792..f68c9362022 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt @@ -100,7 +100,7 @@ class JsExecutableProducer( it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false) } stopwatch.stop() - val compilationOut = CompilationOutputs(mainModule.jsCode, mainModule.jsProgram, mainModule.sourceMap, dependencies) + val compilationOut = mainModule.addDependencies(dependencies) return BuildResult(compilationOut, rebuildModules) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt index fe535703495..b8f953084a8 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt @@ -74,7 +74,7 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { fun fetchCompiledJsCode(artifact: ModuleArtifact) = artifact.artifactsDir?.let { cacheDir -> val jsCode = File(cacheDir, CACHED_MODULE_JS).ifExists { readText() } val sourceMap = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { readText() } - jsCode?.let { CompilationOutputs(it, null, sourceMap) } + jsCode?.let { CompilationOutputs(it, null, null, sourceMap) } } fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputs) = artifact.artifactsDir?.let { cacheDir -> diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index 91c559cbef0..4ffc0ecd3f0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer import org.jetbrains.kotlin.js.util.TextOutputImpl import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.utils.addToStdlib.runIf -import java.io.ByteArrayOutputStream +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import java.io.File import java.util.* @@ -107,19 +107,15 @@ class IrModuleToJsTransformer( private val isEsModules = moduleKind == ModuleKind.ES private val sourceMapInfo = SourceMapsInfo.from(backendContext.configuration) - private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List>>) + private class IrFileExports(val file: IrFile, val exports: List, val tsDeclarations: TypeScriptFragment?) - private fun List.flatExportedDeclarations(): List { - return this.flatMap { data -> data.files.flatMap { it.second } } - } + private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List) private fun associateIrAndExport(modules: Iterable): List { val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules) return modules.map { module -> - val files = module.files.map { file -> - file to exportModelGenerator.generateExportWithExternals(file) - } + val files = exportModelGenerator.generateExportWithExternals(module.files) IrAndExportedDeclarations(module, files) } } @@ -144,9 +140,6 @@ class IrModuleToJsTransformer( fun generateModule(modules: Iterable, modes: Set, relativeRequirePath: Boolean): CompilerResult { val exportData = associateIrAndExport(modules) - val dts = runIf(shouldGenerateTypeScriptDefinitions) { - ExportedModule(mainModuleName, moduleKind, exportData.flatExportedDeclarations()).toTypeScript() - } doStaticMembersLowering(modules) val result = EnumMap(TranslationMode::class.java) @@ -163,39 +156,41 @@ class IrModuleToJsTransformer( result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true) } - return CompilerResult(result, dts) + return CompilerResult(result) } - fun makeJsCodeGeneratorAndDts(modules: Iterable, mode: TranslationMode): Pair { + fun makeJsCodeGenerator(modules: Iterable, mode: TranslationMode): JsCodeGenerator { val exportData = associateIrAndExport(modules) - val dts = runIf(shouldGenerateTypeScriptDefinitions) { - ExportedModule(mainModuleName, moduleKind, exportData.flatExportedDeclarations()).toTypeScript() - } doStaticMembersLowering(modules) if (mode.dce) { eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects) } - return makeJsCodeGeneratorFromIr(exportData, mode) to dts + return makeJsCodeGeneratorFromIr(exportData, mode) } fun makeIrFragmentsGenerators(files: Collection, allModules: Collection): List<() -> JsIrProgramFragment> { val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules) - - val exportData = files.map { it to exportModelGenerator.generateExportWithExternals(it) } + val exportData = exportModelGenerator.generateExportWithExternals(files) doStaticMembersLowering(allModules) - return exportData.map { (file, exports) -> - { generateProgramFragment(file, exports, minimizedMemberNames = false) } + return exportData.map { + { generateProgramFragment(it, minimizedMemberNames = false) } } } - private fun ExportModelGenerator.generateExportWithExternals(irFile: IrFile): List { - val exports = generateExport(irFile) - val additionalExports = backendContext.externalPackageFragment[irFile.symbol]?.let { generateExport(it) } ?: emptyList() - return additionalExports + exports + private fun ExportModelGenerator.generateExportWithExternals(irFiles: Collection): List { + return irFiles.map { irFile -> + val exports = generateExport(irFile) + val additionalExports = backendContext.externalPackageFragment[irFile.symbol]?.let { generateExport(it) } ?: emptyList() + val allExports = additionalExports + exports + val tsDeclarations = runIf(shouldGenerateTypeScriptDefinitions) { + allExports.ifNotEmpty { toTypeScriptFragment(moduleKind) } + } + IrFileExports(irFile, allExports, tsDeclarations) + } } private fun IrModuleFragment.externalModuleName(): String { @@ -213,8 +208,8 @@ class IrModuleToJsTransformer( JsIrModule( data.fragment.safeName, data.fragment.externalModuleName(), - data.files.map { (file, exports) -> - generateProgramFragment(file, exports, mode.minimizedMemberNames) + data.files.map { + generateProgramFragment(it, mode.minimizedMemberNames) } ) } @@ -226,11 +221,7 @@ class IrModuleToJsTransformer( private val generateFilePaths = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_COMMENTS_WITH_FILE_PATH) private val pathPrefixMap = backendContext.configuration.getMap(JSConfigurationKeys.FILE_PATHS_PREFIX_MAP) - private fun generateProgramFragment( - file: IrFile, - exports: List, - minimizedMemberNames: Boolean - ): JsIrProgramFragment { + private fun generateProgramFragment(fileExports: IrFileExports, minimizedMemberNames: Boolean): JsIrProgramFragment { val nameGenerator = JsNameLinkingNamer(backendContext, minimizedMemberNames) val globalNameScope = NameTable() @@ -241,9 +232,9 @@ class IrModuleToJsTransformer( globalNameScope = globalNameScope ) - val result = JsIrProgramFragment(file.fqName.asString()).apply { + val result = JsIrProgramFragment(fileExports.file.fqName.asString()).apply { if (shouldGeneratePolyfills) { - polyfills.statements += backendContext.polyfills.getAllPolyfillsFor(file) + polyfills.statements += backendContext.polyfills.getAllPolyfillsFor(fileExports.file) } } @@ -251,20 +242,17 @@ class IrModuleToJsTransformer( val globalNames = NameTable(globalNameScope) val exportStatements = ExportModelToJsStatements(staticContext, { globalNames.declareFreshName(it, it) }).generateModuleExport( - ExportedModule(mainModuleName, moduleKind, exports), + ExportedModule(mainModuleName, moduleKind, fileExports.exports), internalModuleName, isEsModules ) result.exports.statements += exportStatements - - if (shouldGenerateTypeScriptDefinitions && exports.isNotEmpty()) { - result.dts = exports.toTypeScript(moduleKind) - } + result.dts = fileExports.tsDeclarations val statements = result.declarations.statements - val fileStatements = file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements + val fileStatements = fileExports.file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements if (fileStatements.isNotEmpty()) { var startComment = "" @@ -273,7 +261,7 @@ class IrModuleToJsTransformer( } if (generateRegionComments || generateFilePaths) { - val originalPath = file.path + val originalPath = fileExports.file.path val path = pathPrefixMap.entries .find { (k, _) -> originalPath.startsWith(k) } ?.let { (k, v) -> v + originalPath.substring(k.length) } @@ -303,7 +291,7 @@ class IrModuleToJsTransformer( result.initializers.statements += staticContext.initializerBlock.statements if (mainArguments != null) { - JsMainFunctionDetector(backendContext).getMainFunctionOrNull(file)?.let { + JsMainFunctionDetector(backendContext).getMainFunctionOrNull(fileExports.file)?.let { val jsName = staticContext.getNameForStaticFunction(it) val generateArgv = it.valueParameters.firstOrNull()?.isStringArrayParameter() ?: false val generateContinuation = it.isLoweredSuspendFunction(backendContext) @@ -311,14 +299,14 @@ class IrModuleToJsTransformer( } } - backendContext.testFunsPerFile[file]?.let { + backendContext.testFunsPerFile[fileExports.file]?.let { result.testFunInvocation = JsInvocation(staticContext.getNameForStaticFunction(it).makeRef()).makeStmt() result.suiteFn = staticContext.getNameForStaticFunction(backendContext.suiteFun!!.owner) } result.importedModules += nameGenerator.importedModules - val definitionSet = file.declarations.toSet() + val definitionSet = fileExports.file.declarations.toSet() fun computeTag(declaration: IrDeclaration): String? { val tag = (backendContext.irFactory as IdSignatureRetriever).declarationSignature(declaration)?.toString() @@ -341,7 +329,7 @@ class IrModuleToJsTransformer( result.imports[tag] = importExpression } - file.declarations.forEach { + fileExports.file.declarations.forEach { computeTag(it)?.let { tag -> result.definitions += tag } @@ -422,7 +410,7 @@ private fun generateWrappedModuleBody( } } - return CompilationOutputs(mainModule.jsCode, mainModule.jsProgram, mainModule.sourceMap, dependencies) + return mainModule.addDependencies(dependencies) } else { return generateSingleWrappedModuleBody( mainModuleName, @@ -484,6 +472,7 @@ fun generateSingleWrappedModuleBody( return CompilationOutputs( jsCode.toString(), + fragments.mapNotNull { it.dts }.ifNotEmpty { joinTypeScriptFragments() }, program.takeIf { outJsProgram }, sourceMapBuilder?.build() ) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt index 76208bf2079..84dfc664603 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs +import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment import org.jetbrains.kotlin.ir.backend.js.utils.toJsIdentifier import org.jetbrains.kotlin.js.backend.ast.* import java.io.File @@ -16,7 +17,7 @@ class JsIrProgramFragment(val packageFqn: String) { val exports = JsCompositeBlock() val importedModules = mutableListOf() val imports = mutableMapOf() - var dts: String? = null + var dts: TypeScriptFragment? = null val classes = mutableMapOf() val initializers = JsCompositeBlock() var mainFunction: JsStatement? = null diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt index 3d6659d7ce2..85fd95de809 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils.serialization +import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrIcClassModel import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope @@ -81,7 +82,9 @@ class JsIrAstDeserializer : JsAstDeserializerBase() { fragment.suiteFn = deserializeName(proto.suiteFunction) } - fragment.dts = proto.dts + if (proto.hasDts()) { + fragment.dts = TypeScriptFragment(proto.dts) + } fragment.definitions += proto.definitionsList.map { deserializeString(it) } return fragment diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt index dab00d0eb55..6166d9af54d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt @@ -81,7 +81,7 @@ class JsIrAstSerializer: JsAstSerializerBase() { } fragment.dts?.let { - fragmentBuilder.dts = it + fragmentBuilder.dts = it.raw } fragment.suiteFn?.let { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt index 2b5e21fd04b..6866833684f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt @@ -105,8 +105,7 @@ class JsIrBackendFacade( relativeRequirePath = false ) jsExecutableProducer.buildExecutable(it.perModule, true).compilationOut - }, - tsDefinitions = null + } ) return BinaryArtifacts.Js.JsIrArtifact( outputFile, compiledModule, testServices.jsIrIncrementalDataProvider.getCacheForModule(module) @@ -164,7 +163,8 @@ class JsIrBackendFacade( val isEsModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives || module.directives[JsEnvironmentConfigurationDirectives.MODULE_KIND].contains(ModuleKind.ES) - val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, TranslationMode.FULL) + module.kind.extension) + val outputFile = + File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, TranslationMode.FULL) + module.kind.extension) val transformer = IrModuleToJsTransformer( loweredIr.context, @@ -174,15 +174,15 @@ class JsIrBackendFacade( isEsModules && granularity != JsGenerationGranularity.WHOLE_PROGRAM ) ) - // If runIrDce then include DCE results - // If perModuleOnly then skip whole program - // (it.dce => runIrDce) && (perModuleOnly => it.perModule) - val translationModes = TranslationMode.values() - .filter { (it.dce || !onlyIrDce) && (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) } - .filter { it.dce == it.minimizedMemberNames } - .toSet() - val compilationOut = transformer.generateModule(loweredIr.allModules, translationModes, false) - return BinaryArtifacts.Js.JsIrArtifact(outputFile, compilationOut).dump(module) + // If runIrDce then include DCE results + // If perModuleOnly then skip whole program + // (it.dce => runIrDce) && (perModuleOnly => it.perModule) + val translationModes = TranslationMode.values() + .filter { (it.dce || !onlyIrDce) && (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) } + .filter { it.dce == it.minimizedMemberNames } + .toSet() + val compilationOut = transformer.generateModule(loweredIr.allModules, translationModes, false) + return BinaryArtifacts.Js.JsIrArtifact(outputFile, compilationOut).dump(module) } private fun IrModuleFragment.resolveTestPathes() { @@ -195,7 +195,7 @@ class JsIrBackendFacade( val filesToLoad = module.files.takeIf { !firstTimeCompilation }?.map { "/${it.relativePath}" }?.toSet() val messageLogger = configuration.irMessageLogger - val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImplForJsIC(WholeWorldStageController()),) + val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImplForJsIC(WholeWorldStageController())) val moduleDescriptor = testServices.moduleDescriptorProvider.getModuleDescriptor(module) val mainModuleLib = testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(moduleDescriptor) @@ -244,9 +244,13 @@ class JsIrBackendFacade( } if (generateDts) { + val tsFiles = compilerResult.outputs.entries.associate { it.value.getFullTsDefinition(moduleId, moduleKind) to it.key } + val tsDefinitions = tsFiles.entries.singleOrNull()?.key + ?: error("[${tsFiles.values.joinToString { it.name }}] make different TypeScript") + outputFile .withReplacedExtensionOrNull("_v5${moduleKind.extension}", ".d.ts")!! - .write(compilerResult.tsDefinitions ?: error("No ts definitions")) + .write(tsDefinitions) } return this