[K/JS] Implement file merging for clashed file during per-file compilation
This commit is contained in:
@@ -17,9 +17,6 @@ class JsMapping : DefaultMapping() {
|
|||||||
val esClassWhichNeedBoxParameters = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, Boolean>()
|
val esClassWhichNeedBoxParameters = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, Boolean>()
|
||||||
val esClassToPossibilityForOptimization = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, MutableReference<Boolean>>()
|
val esClassToPossibilityForOptimization = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, MutableReference<Boolean>>()
|
||||||
|
|
||||||
// Check if we need concurrency here
|
|
||||||
val chunkToOriginalFile = WeakHashMap<IrFile, IrFile>()
|
|
||||||
|
|
||||||
val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
||||||
val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
||||||
val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class JsIrCompilerWithIC(
|
|||||||
allModules: Collection<IrModuleFragment>,
|
allModules: Collection<IrModuleFragment>,
|
||||||
dirtyFiles: Collection<IrFile>,
|
dirtyFiles: Collection<IrFile>,
|
||||||
mainArguments: List<String>?
|
mainArguments: List<String>?
|
||||||
): List<() -> List<JsIrProgramFragment>> {
|
): List<() -> JsIrProgramFragments> {
|
||||||
val shouldGeneratePolyfills = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_POLYFILLS)
|
val shouldGeneratePolyfills = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_POLYFILLS)
|
||||||
|
|
||||||
allModules.forEach {
|
allModules.forEach {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.*
|
import org.jetbrains.kotlin.ir.backend.js.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
@@ -33,7 +34,7 @@ fun interface JsIrCompilerICInterface {
|
|||||||
allModules: Collection<IrModuleFragment>,
|
allModules: Collection<IrModuleFragment>,
|
||||||
dirtyFiles: Collection<IrFile>,
|
dirtyFiles: Collection<IrFile>,
|
||||||
mainArguments: List<String>?
|
mainArguments: List<String>?
|
||||||
): List<() -> List<JsIrProgramFragment>>
|
): List<() -> JsIrProgramFragments>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interface JsIrCompilerICInterfaceFactory {
|
fun interface JsIrCompilerICInterfaceFactory {
|
||||||
@@ -616,7 +617,7 @@ class CacheUpdater(
|
|||||||
private fun commitCacheAndBuildModuleArtifacts(
|
private fun commitCacheAndBuildModuleArtifacts(
|
||||||
incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>,
|
incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>,
|
||||||
moduleNames: Map<KotlinLibraryFile, String>,
|
moduleNames: Map<KotlinLibraryFile, String>,
|
||||||
rebuiltFileFragments: KotlinSourceFileMap<List<JsIrProgramFragment>>
|
rebuiltFileFragments: KotlinSourceFileMap<JsIrProgramFragments>
|
||||||
): List<ModuleArtifact> = stopwatch.measure("Incremental cache - committing artifacts") {
|
): List<ModuleArtifact> = stopwatch.measure("Incremental cache - committing artifacts") {
|
||||||
incrementalCacheArtifacts.map { (libFile, incrementalCacheArtifact) ->
|
incrementalCacheArtifacts.map { (libFile, incrementalCacheArtifact) ->
|
||||||
incrementalCacheArtifact.buildModuleArtifactAndCommitCache(
|
incrementalCacheArtifact.buildModuleArtifactAndCommitCache(
|
||||||
@@ -630,7 +631,7 @@ class CacheUpdater(
|
|||||||
compilerForIC: JsIrCompilerICInterface,
|
compilerForIC: JsIrCompilerICInterface,
|
||||||
loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>,
|
loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>,
|
||||||
dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>>
|
dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>>
|
||||||
): MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> List<JsIrProgramFragment>>> =
|
): MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> JsIrProgramFragments>> =
|
||||||
stopwatch.measure("Processing IR - lowering") {
|
stopwatch.measure("Processing IR - lowering") {
|
||||||
val dirtyFilesForCompiling = mutableListOf<IrFile>()
|
val dirtyFilesForCompiling = mutableListOf<IrFile>()
|
||||||
val dirtyFilesForRestoring = mutableListOf<Pair<KotlinLibraryFile, KotlinSourceFile>>()
|
val dirtyFilesForRestoring = mutableListOf<Pair<KotlinLibraryFile, KotlinSourceFile>>()
|
||||||
@@ -737,7 +738,7 @@ class CacheUpdater(
|
|||||||
private data class FragmentGenerators(
|
private data class FragmentGenerators(
|
||||||
val incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>,
|
val incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>,
|
||||||
val moduleNames: Map<KotlinLibraryFile, String>,
|
val moduleNames: Map<KotlinLibraryFile, String>,
|
||||||
val generators: MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> List<JsIrProgramFragment>>>
|
val generators: MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> JsIrProgramFragments>>
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun loadIrAndMakeIrFragmentGenerators(): FragmentGenerators {
|
private fun loadIrAndMakeIrFragmentGenerators(): FragmentGenerators {
|
||||||
@@ -751,9 +752,9 @@ class CacheUpdater(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateIrFragments(
|
private fun generateIrFragments(
|
||||||
generators: MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> List<JsIrProgramFragment>>>
|
generators: MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> JsIrProgramFragments>>
|
||||||
): KotlinSourceFileMap<List<JsIrProgramFragment>> = stopwatch.measure("Processing IR - generating program fragments") {
|
): KotlinSourceFileMap<JsIrProgramFragments> = stopwatch.measure("Processing IR - generating program fragments") {
|
||||||
val rebuiltFragments = KotlinSourceFileMutableMap<List<JsIrProgramFragment>>()
|
val rebuiltFragments = KotlinSourceFileMutableMap<JsIrProgramFragments>()
|
||||||
while (generators.isNotEmpty()) {
|
while (generators.isNotEmpty()) {
|
||||||
val (libFile, srcFile, fragmentGenerator) = generators.removeFirst()
|
val (libFile, srcFile, fragmentGenerator) = generators.removeFirst()
|
||||||
rebuiltFragments[libFile, srcFile] = fragmentGenerator()
|
rebuiltFragments[libFile, srcFile] = fragmentGenerator()
|
||||||
@@ -782,7 +783,7 @@ fun rebuildCacheForDirtyFiles(
|
|||||||
irFactory: IrFactory,
|
irFactory: IrFactory,
|
||||||
exportedDeclarations: Set<FqName>,
|
exportedDeclarations: Set<FqName>,
|
||||||
mainArguments: List<String>?,
|
mainArguments: List<String>?,
|
||||||
): Pair<IrModuleFragment, List<Pair<IrFile, List<JsIrProgramFragment>>>> {
|
): Pair<IrModuleFragment, List<Pair<IrFile, JsIrProgramFragments>>> {
|
||||||
val internationService = IrInterningService()
|
val internationService = IrInterningService()
|
||||||
val emptyMetadata = object : KotlinSourceFileExports() {
|
val emptyMetadata = object : KotlinSourceFileExports() {
|
||||||
override val inverseDependencies = KotlinSourceFileMap<Set<IdSignature>>(emptyMap())
|
override val inverseDependencies = KotlinSourceFileMap<Set<IdSignature>>(emptyMap())
|
||||||
|
|||||||
+7
-7
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.serializeTo
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.serializeTo
|
||||||
import org.jetbrains.kotlin.konan.file.use
|
import org.jetbrains.kotlin.konan.file.use
|
||||||
import org.jetbrains.kotlin.utils.newHashSetWithExpectedSize
|
import org.jetbrains.kotlin.utils.newHashSetWithExpectedSize
|
||||||
@@ -15,7 +15,7 @@ import java.io.File
|
|||||||
internal sealed class SourceFileCacheArtifact(val srcFile: KotlinSourceFile, val binaryAstFile: File) {
|
internal sealed class SourceFileCacheArtifact(val srcFile: KotlinSourceFile, val binaryAstFile: File) {
|
||||||
abstract fun commitMetadata()
|
abstract fun commitMetadata()
|
||||||
|
|
||||||
fun commitBinaryAst(fragments: List<JsIrProgramFragment>) {
|
fun commitBinaryAst(fragments: JsIrProgramFragments) {
|
||||||
binaryAstFile.parentFile?.mkdirs()
|
binaryAstFile.parentFile?.mkdirs()
|
||||||
BufferedOutputStream(binaryAstFile.outputStream()).use {
|
BufferedOutputStream(binaryAstFile.outputStream()).use {
|
||||||
fragments.serializeTo(it)
|
fragments.serializeTo(it)
|
||||||
@@ -30,7 +30,7 @@ internal sealed class SourceFileCacheArtifact(val srcFile: KotlinSourceFile, val
|
|||||||
srcFile: KotlinSourceFile,
|
srcFile: KotlinSourceFile,
|
||||||
binaryAstFile: File,
|
binaryAstFile: File,
|
||||||
private val metadataFile: File,
|
private val metadataFile: File,
|
||||||
private val encodedMetadata: ByteArray
|
private val encodedMetadata: ByteArray,
|
||||||
) : SourceFileCacheArtifact(srcFile, binaryAstFile) {
|
) : SourceFileCacheArtifact(srcFile, binaryAstFile) {
|
||||||
override fun commitMetadata() {
|
override fun commitMetadata() {
|
||||||
metadataFile.parentFile?.mkdirs()
|
metadataFile.parentFile?.mkdirs()
|
||||||
@@ -41,7 +41,7 @@ internal sealed class SourceFileCacheArtifact(val srcFile: KotlinSourceFile, val
|
|||||||
class RemoveMetadata(
|
class RemoveMetadata(
|
||||||
srcFile: KotlinSourceFile,
|
srcFile: KotlinSourceFile,
|
||||||
binaryAstFile: File,
|
binaryAstFile: File,
|
||||||
private val metadataFile: File
|
private val metadataFile: File,
|
||||||
) : SourceFileCacheArtifact(srcFile, binaryAstFile) {
|
) : SourceFileCacheArtifact(srcFile, binaryAstFile) {
|
||||||
override fun commitMetadata() {
|
override fun commitMetadata() {
|
||||||
metadataFile.delete()
|
metadataFile.delete()
|
||||||
@@ -53,13 +53,13 @@ internal class IncrementalCacheArtifact(
|
|||||||
private val artifactsDir: File,
|
private val artifactsDir: File,
|
||||||
private val forceRebuildJs: Boolean,
|
private val forceRebuildJs: Boolean,
|
||||||
private val srcCacheActions: List<SourceFileCacheArtifact>,
|
private val srcCacheActions: List<SourceFileCacheArtifact>,
|
||||||
private val externalModuleName: String?
|
private val externalModuleName: String?,
|
||||||
) {
|
) {
|
||||||
fun getSourceFiles() = srcCacheActions.mapTo(newHashSetWithExpectedSize(srcCacheActions.size)) { it.srcFile }
|
fun getSourceFiles() = srcCacheActions.mapTo(newHashSetWithExpectedSize(srcCacheActions.size)) { it.srcFile }
|
||||||
|
|
||||||
fun buildModuleArtifactAndCommitCache(
|
fun buildModuleArtifactAndCommitCache(
|
||||||
moduleName: String,
|
moduleName: String,
|
||||||
rebuiltFileFragments: Map<KotlinSourceFile, List<JsIrProgramFragment>>,
|
rebuiltFileFragments: Map<KotlinSourceFile, JsIrProgramFragments>,
|
||||||
): ModuleArtifact {
|
): ModuleArtifact {
|
||||||
val fileArtifacts = srcCacheActions.map { srcFileAction ->
|
val fileArtifacts = srcCacheActions.map { srcFileAction ->
|
||||||
val rebuiltFileFragment = rebuiltFileFragments[srcFileAction.srcFile]
|
val rebuiltFileFragment = rebuiltFileFragments[srcFileAction.srcFile]
|
||||||
@@ -67,7 +67,7 @@ internal class IncrementalCacheArtifact(
|
|||||||
srcFileAction.commitBinaryAst(rebuiltFileFragment)
|
srcFileAction.commitBinaryAst(rebuiltFileFragment)
|
||||||
}
|
}
|
||||||
srcFileAction.commitMetadata()
|
srcFileAction.commitMetadata()
|
||||||
SrcFileArtifact(srcFileAction.srcFile.path, rebuiltFileFragment ?: emptyList(), srcFileAction.binaryAstFile)
|
SrcFileArtifact(srcFileAction.srcFile.path, rebuiltFileFragment, srcFileAction.binaryAstFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModuleArtifact(moduleName, fileArtifacts, artifactsDir, forceRebuildJs, externalModuleName)
|
return ModuleArtifact(moduleName, fileArtifacts, artifactsDir, forceRebuildJs, externalModuleName)
|
||||||
|
|||||||
+140
-102
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.serialization.cityHash64
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||||
import org.jetbrains.kotlin.protobuf.CodedOutputStream
|
import org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.butIf
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -20,6 +19,48 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
private const val CACHED_EXPORT_FILE_JS = "file.export.js"
|
private const val CACHED_EXPORT_FILE_JS = "file.export.js"
|
||||||
private const val CACHED_FILE_JS_MAP = "file.js.map"
|
private const val CACHED_FILE_JS_MAP = "file.js.map"
|
||||||
private const val CACHED_FILE_D_TS = "file.d.ts"
|
private const val CACHED_FILE_D_TS = "file.d.ts"
|
||||||
|
|
||||||
|
private val moduleFragmentToExternalName = ModuleFragmentToExternalName(emptyMap())
|
||||||
|
|
||||||
|
private fun JsIrProgramFragment.getMainFragmentExternalName(moduleArtifact: ModuleArtifact) =
|
||||||
|
moduleFragmentToExternalName.getExternalNameFor(name, packageFqn, moduleArtifact.moduleExternalName)
|
||||||
|
|
||||||
|
private fun JsIrProgramFragment.getExportFragmentExternalName(moduleArtifact: ModuleArtifact) =
|
||||||
|
moduleFragmentToExternalName.getExternalNameForExporterFile(name, packageFqn, moduleArtifact.moduleExternalName)
|
||||||
|
|
||||||
|
private fun SrcFileArtifact.loadJsIrModuleHeaders(moduleArtifact: ModuleArtifact) = with(loadJsIrFragments()!!) {
|
||||||
|
LoadedJsIrModuleHeaders(
|
||||||
|
mainFragment.run {
|
||||||
|
asIrModuleHeader(
|
||||||
|
getMainFragmentExternalName(moduleArtifact),
|
||||||
|
importWithEffectIn = runIf(hasEffect) { moduleArtifact.moduleExternalName }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
exportFragment?.run {
|
||||||
|
asIrModuleHeader(
|
||||||
|
mainFragment.getExportFragmentExternalName(moduleArtifact),
|
||||||
|
reexportedIn = moduleArtifact.moduleExternalName
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JsIrProgramFragment.asIrModuleHeader(
|
||||||
|
moduleName: String,
|
||||||
|
reexportedIn: String? = null,
|
||||||
|
importWithEffectIn: String? = null,
|
||||||
|
): JsIrModuleHeader {
|
||||||
|
return JsIrModuleHeader(
|
||||||
|
moduleName = moduleName,
|
||||||
|
externalModuleName = moduleName,
|
||||||
|
definitions = definitions,
|
||||||
|
nameBindings = nameBindings.mapValues { v -> v.value.toString() },
|
||||||
|
optionalCrossModuleImports = optionalCrossModuleImports,
|
||||||
|
reexportedInModuleWithName = reexportedIn,
|
||||||
|
importedWithEffectInModuleWithName = importWithEffectIn,
|
||||||
|
associatedModule = JsIrModule(moduleName, moduleName, listOf(this), reexportedIn)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class CachedFileInfo(val moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader?) : CacheInfo {
|
sealed class CachedFileInfo(val moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader?) : CacheInfo {
|
||||||
@@ -30,6 +71,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
if (moduleHeader != null) jsIrHeader = moduleHeader
|
if (moduleHeader != null) jsIrHeader = moduleHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun loadJsIrModule(): JsIrModule
|
||||||
|
|
||||||
sealed class SerializableCachedFileInfo(
|
sealed class SerializableCachedFileInfo(
|
||||||
moduleArtifact: ModuleArtifact,
|
moduleArtifact: ModuleArtifact,
|
||||||
@@ -37,19 +79,60 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
moduleHeader: JsIrModuleHeader?
|
moduleHeader: JsIrModuleHeader?
|
||||||
) : CachedFileInfo(moduleArtifact, moduleHeader) {
|
) : CachedFileInfo(moduleArtifact, moduleHeader) {
|
||||||
fun getArtifactWithName(name: String): File? = moduleArtifact.artifactsDir?.let { File(it, "$filePrefix.$name") }
|
fun getArtifactWithName(name: String): File? = moduleArtifact.artifactsDir?.let { File(it, "$filePrefix.$name") }
|
||||||
private val filePrefix by lazy(LazyThreadSafetyMode.NONE) { fileArtifact.srcFilePath.run { "${substringAfterLast('/')}.${cityHash64()}" } }
|
protected open val filePrefix by lazy(LazyThreadSafetyMode.NONE) { fileArtifact.srcFilePath.run { "${substringAfterLast('/')}.${cityHash64()}" } }
|
||||||
|
|
||||||
|
override fun loadJsIrModule(): JsIrModule {
|
||||||
|
val fragments = fileArtifact.loadJsIrFragments()!!
|
||||||
|
val isExportFileCachedInfo = this is ExportFileCachedInfo
|
||||||
|
return JsIrModule(
|
||||||
|
jsIrHeader.moduleName,
|
||||||
|
jsIrHeader.externalModuleName,
|
||||||
|
listOf(if (isExportFileCachedInfo) fragments.exportFragment!! else fragments.mainFragment),
|
||||||
|
runIf(isExportFileCachedInfo) { moduleArtifact.moduleSafeName }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainFileCachedInfo(moduleArtifact: ModuleArtifact, fileArtifact: SrcFileArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
open class MainFileCachedInfo(moduleArtifact: ModuleArtifact, fileArtifact: SrcFileArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
||||||
SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) {
|
SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) {
|
||||||
var exportFileCachedInfo: ExportFileCachedInfo? = null
|
var exportFileCachedInfo: ExportFileCachedInfo? = null
|
||||||
|
|
||||||
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) }
|
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) }
|
||||||
val moduleHeaderArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(JS_MODULE_HEADER) }
|
val moduleHeaderArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(JS_MODULE_HEADER) }
|
||||||
val sourceMapFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS_MAP) }
|
val sourceMapFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS_MAP) }
|
||||||
|
|
||||||
|
class Merged(private val cachedFileInfos: List<MainFileCachedInfo>) :
|
||||||
|
MainFileCachedInfo(cachedFileInfos.first().moduleArtifact, cachedFileInfos.first().fileArtifact) {
|
||||||
|
override val filePrefix by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
val hash = cachedFileInfos.map { it.fileArtifact.srcFilePath }.sorted().joinToString().cityHash64()
|
||||||
|
fileArtifact.srcFilePath.run { "${substringAfterLast('/')}.$hash.merged" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadJsIrModule(): JsIrModule = cachedFileInfos.map { it.loadJsIrModule() }.merge()
|
||||||
|
|
||||||
|
init {
|
||||||
|
assert(cachedFileInfos.size > 1) { "Merge is unnecessary" }
|
||||||
|
val isModified = cachedFileInfos.any { it.fileArtifact.isModified() }
|
||||||
|
val mainAndExportHeaders = when {
|
||||||
|
isModified -> cachedFileInfos.map { it.fileArtifact.loadJsIrModuleHeaders(moduleArtifact) }
|
||||||
|
else -> cachedFileInfos.map { LoadedJsIrModuleHeaders(it.jsIrHeader, it.exportFileCachedInfo?.jsIrHeader) }
|
||||||
|
}
|
||||||
|
val (mainHeaders, exportHeaders) = mainAndExportHeaders.map(LoadedJsIrModuleHeaders::toPair).unzip()
|
||||||
|
|
||||||
|
jsIrHeader = mainHeaders.merge()
|
||||||
|
exportFileCachedInfo = exportHeaders.filterNotNull().takeIf { it.isNotEmpty() }
|
||||||
|
?.let {
|
||||||
|
ExportFileCachedInfo.Merged(
|
||||||
|
filePrefix,
|
||||||
|
it.merge(),
|
||||||
|
cachedFileInfos.mapNotNull(MainFileCachedInfo::exportFileCachedInfo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExportFileCachedInfo(
|
open class ExportFileCachedInfo(
|
||||||
moduleArtifact: ModuleArtifact,
|
moduleArtifact: ModuleArtifact,
|
||||||
fileArtifact: SrcFileArtifact,
|
fileArtifact: SrcFileArtifact,
|
||||||
moduleHeader: JsIrModuleHeader? = null,
|
moduleHeader: JsIrModuleHeader? = null,
|
||||||
@@ -57,6 +140,14 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
) : SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) {
|
) : SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) {
|
||||||
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_EXPORT_FILE_JS) }
|
val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_EXPORT_FILE_JS) }
|
||||||
val dtsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_D_TS) }
|
val dtsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_D_TS) }
|
||||||
|
|
||||||
|
class Merged(
|
||||||
|
override val filePrefix: String,
|
||||||
|
moduleHeader: JsIrModuleHeader,
|
||||||
|
private val cachedFileInfos: List<ExportFileCachedInfo>,
|
||||||
|
) : ExportFileCachedInfo(cachedFileInfos.first().moduleArtifact, cachedFileInfos.first().fileArtifact, moduleHeader) {
|
||||||
|
override fun loadJsIrModule(): JsIrModule = cachedFileInfos.map { it.loadJsIrModule() }.merge()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModuleProxyFileCachedInfo(moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
class ModuleProxyFileCachedInfo(moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader? = null) :
|
||||||
@@ -66,51 +157,18 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
val moduleHeaderArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(JS_MODULE_HEADER) }
|
val moduleHeaderArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(JS_MODULE_HEADER) }
|
||||||
|
|
||||||
private fun getArtifactWithName(name: String): File? = moduleArtifact.artifactsDir?.let { File(it, "entry.$name") }
|
private fun getArtifactWithName(name: String): File? = moduleArtifact.artifactsDir?.let { File(it, "entry.$name") }
|
||||||
|
|
||||||
|
override fun loadJsIrModule(): JsIrModule {
|
||||||
|
return generateProxyIrModuleWith(
|
||||||
|
jsIrHeader.externalModuleName,
|
||||||
|
jsIrHeader.externalModuleName,
|
||||||
|
jsIrHeader.importedWithEffectInModuleWithName
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val headerToCachedInfo = hashMapOf<JsIrModuleHeader, CachedFileInfo>()
|
private val headerToCachedInfo = hashMapOf<JsIrModuleHeader, CachedFileInfo>()
|
||||||
private val moduleFragmentToExternalName = ModuleFragmentToExternalName(emptyMap())
|
|
||||||
|
|
||||||
private fun JsIrProgramFragment.getMainFragmentExternalName(moduleArtifact: ModuleArtifact) =
|
|
||||||
moduleFragmentToExternalName.getExternalNameFor(name, packageFqn, moduleArtifact.moduleExternalName)
|
|
||||||
|
|
||||||
private fun JsIrProgramFragment.getExportFragmentExternalName(moduleArtifact: ModuleArtifact) =
|
|
||||||
moduleFragmentToExternalName.getExternalNameForExporterFile(name, packageFqn, moduleArtifact.moduleExternalName)
|
|
||||||
|
|
||||||
private fun JsIrProgramFragment.asIrModuleHeader(
|
|
||||||
moduleName: String,
|
|
||||||
reexportedIn: String? = null,
|
|
||||||
importWithEffectIn: String? = null,
|
|
||||||
): JsIrModuleHeader {
|
|
||||||
return JsIrModuleHeader(
|
|
||||||
moduleName = moduleName,
|
|
||||||
externalModuleName = moduleName,
|
|
||||||
definitions = definitions,
|
|
||||||
nameBindings = nameBindings.mapValues { v -> v.value.toString() },
|
|
||||||
optionalCrossModuleImports = optionalCrossModuleImports,
|
|
||||||
reexportedInModuleWithName = reexportedIn,
|
|
||||||
importedWithEffectInModuleWithName = importWithEffectIn,
|
|
||||||
associatedModule = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun SrcFileArtifact.loadJsIrModuleHeaders(moduleArtifact: ModuleArtifact) = with(loadJsIrFragments()) {
|
|
||||||
LoadedJsIrModuleHeaders(
|
|
||||||
mainFragment.run {
|
|
||||||
asIrModuleHeader(
|
|
||||||
getMainFragmentExternalName(moduleArtifact),
|
|
||||||
importWithEffectIn = runIf(hasEffect) { moduleArtifact.moduleExternalName }
|
|
||||||
)
|
|
||||||
},
|
|
||||||
exportFragment?.run {
|
|
||||||
asIrModuleHeader(
|
|
||||||
mainFragment.getExportFragmentExternalName(moduleArtifact),
|
|
||||||
reexportedIn = moduleArtifact.moduleExternalName
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : CachedFileInfo> CodedInputStream.loadSingleCachedFileInfo(cachedFileInfo: T): T = cachedFileInfo.also {
|
private fun <T : CachedFileInfo> CodedInputStream.loadSingleCachedFileInfo(cachedFileInfo: T): T = cachedFileInfo.also {
|
||||||
val moduleName = readString()
|
val moduleName = readString()
|
||||||
@@ -142,14 +200,13 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
private fun <T> CachedFileInfo.MainFileCachedInfo.readModuleHeaderCache(f: CodedInputStream.() -> T): T? =
|
private fun <T> CachedFileInfo.MainFileCachedInfo.readModuleHeaderCache(f: CodedInputStream.() -> T): T? =
|
||||||
moduleHeaderArtifact?.useCodedInputIfExists(f)
|
moduleHeaderArtifact?.useCodedInputIfExists(f)
|
||||||
|
|
||||||
private fun ModuleArtifact.fetchFileInfoFor(fileArtifact: SrcFileArtifact): List<CachedFileInfo>? {
|
private fun ModuleArtifact.fetchFileInfoFor(fileArtifact: SrcFileArtifact): CachedFileInfo.MainFileCachedInfo? {
|
||||||
val mainFileCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact)
|
val mainFileCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact)
|
||||||
|
|
||||||
return mainFileCachedFileInfo.readModuleHeaderCache {
|
return mainFileCachedFileInfo.readModuleHeaderCache {
|
||||||
mainFileCachedFileInfo.run {
|
mainFileCachedFileInfo.apply {
|
||||||
exportFileCachedInfo = fetchFileInfoForExportedPart(this)
|
exportFileCachedInfo = fetchFileInfoForExportedPart(this)
|
||||||
loadSingleCachedFileInfo(this)
|
loadSingleCachedFileInfo(this)
|
||||||
listOfNotNull(exportFileCachedInfo, this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,13 +256,13 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ModuleArtifact.loadFileInfoFor(fileArtifact: SrcFileArtifact): List<CachedFileInfo> {
|
private fun ModuleArtifact.loadFileInfoFor(fileArtifact: SrcFileArtifact): CachedFileInfo.MainFileCachedInfo {
|
||||||
val headers = fileArtifact.loadJsIrModuleHeaders(this)
|
val headers = fileArtifact.loadJsIrModuleHeaders(this)
|
||||||
|
|
||||||
val mainCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact, headers.mainHeader)
|
val mainCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact, headers.mainHeader)
|
||||||
|
|
||||||
if (headers.exportHeader != null) {
|
if (headers.exportHeader != null) {
|
||||||
val tsDeclarationsHash = fileArtifact.loadJsIrFragments().exportFragment?.dts?.raw?.cityHash64()
|
val tsDeclarationsHash = fileArtifact.loadJsIrFragments()?.exportFragment?.dts?.raw?.cityHash64()
|
||||||
val cachedExportFileInfo = mainCachedFileInfo.readModuleHeaderCache { fetchFileInfoForExportedPart(mainCachedFileInfo) }
|
val cachedExportFileInfo = mainCachedFileInfo.readModuleHeaderCache { fetchFileInfoForExportedPart(mainCachedFileInfo) }
|
||||||
mainCachedFileInfo.exportFileCachedInfo = if (cachedExportFileInfo?.tsDeclarationsHash != tsDeclarationsHash) {
|
mainCachedFileInfo.exportFileCachedInfo = if (cachedExportFileInfo?.tsDeclarationsHash != tsDeclarationsHash) {
|
||||||
CachedFileInfo.ExportFileCachedInfo(
|
CachedFileInfo.ExportFileCachedInfo(
|
||||||
@@ -219,7 +276,7 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return listOfNotNull(mainCachedFileInfo.exportFileCachedInfo, mainCachedFileInfo)
|
return mainCachedFileInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
private val CachedFileInfo.cachedFiles: CachedFileArtifacts?
|
private val CachedFileInfo.cachedFiles: CachedFileArtifacts?
|
||||||
@@ -245,59 +302,41 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
compilationOutputs.writeJsCodeIntoModuleCache(jsCodeFile, jsMapFile)
|
compilationOutputs.writeJsCodeIntoModuleCache(jsCodeFile, jsMapFile)
|
||||||
} ?: compilationOutputs
|
} ?: compilationOutputs
|
||||||
|
|
||||||
override fun loadJsIrModule(cacheInfo: CachedFileInfo): JsIrModule {
|
override fun loadJsIrModule(cacheInfo: CachedFileInfo): JsIrModule =
|
||||||
if (cacheInfo !is CachedFileInfo.SerializableCachedFileInfo) {
|
cacheInfo.loadJsIrModule()
|
||||||
return generateProxyIrModuleWith(
|
|
||||||
cacheInfo.jsIrHeader.externalModuleName,
|
|
||||||
cacheInfo.jsIrHeader.externalModuleName,
|
|
||||||
cacheInfo.jsIrHeader.importedWithEffectInModuleWithName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val fragments = cacheInfo.fileArtifact.loadJsIrFragments()
|
|
||||||
val isExportFileCachedInfo = cacheInfo is CachedFileInfo.ExportFileCachedInfo
|
|
||||||
return JsIrModule(
|
|
||||||
cacheInfo.jsIrHeader.moduleName,
|
|
||||||
cacheInfo.jsIrHeader.externalModuleName,
|
|
||||||
listOf(if (isExportFileCachedInfo) fragments.exportFragment!! else fragments.mainFragment),
|
|
||||||
runIf(isExportFileCachedInfo) { cacheInfo.moduleArtifact.moduleSafeName }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadProgramHeadersFromCache(): List<CachedFileInfo> {
|
override fun loadProgramHeadersFromCache(): List<CachedFileInfo> {
|
||||||
var someModuleHasEffect = false
|
|
||||||
val mainModuleArtifact = moduleArtifacts.last()
|
val mainModuleArtifact = moduleArtifacts.last()
|
||||||
return moduleArtifacts
|
|
||||||
.flatMap { moduleArtifact ->
|
|
||||||
var hasModuleLevelEffect = false
|
|
||||||
var hasFileWithJsExportedDeclaration = false
|
|
||||||
moduleArtifact.fileArtifacts
|
|
||||||
.flatMap { srcFileArtifact ->
|
|
||||||
val cachedFileInfo = if (srcFileArtifact.isModified())
|
|
||||||
moduleArtifact.loadFileInfoFor(srcFileArtifact)
|
|
||||||
else
|
|
||||||
moduleArtifact.fetchFileInfoFor(srcFileArtifact) ?: moduleArtifact.loadFileInfoFor(srcFileArtifact)
|
|
||||||
|
|
||||||
if (!hasFileWithJsExportedDeclaration && cachedFileInfo.hasExportFile()) {
|
val perFileGenerator = object : PerFileGenerator<ModuleArtifact, SrcFileArtifact, CachedFileInfo> {
|
||||||
hasFileWithJsExportedDeclaration = true
|
override val mainModuleName get() = mainModuleArtifact.moduleExternalName
|
||||||
}
|
|
||||||
if (!hasModuleLevelEffect && cachedFileInfo.hasModuleLevelEffect()) {
|
|
||||||
someModuleHasEffect = true
|
|
||||||
hasModuleLevelEffect = true
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedFileInfo
|
override val ModuleArtifact.isMain get() = this === mainModuleArtifact
|
||||||
}
|
override val ModuleArtifact.fileList get() = fileArtifacts
|
||||||
.butIf(hasFileWithJsExportedDeclaration || hasModuleLevelEffect || (someModuleHasEffect && moduleArtifact === mainModuleArtifact)) { list ->
|
|
||||||
val importWithEffectIn = mainModuleArtifact.moduleExternalName.takeIf {
|
override val CachedFileInfo.artifactName get() = jsIrHeader.externalModuleName
|
||||||
hasModuleLevelEffect && moduleArtifact !== mainModuleArtifact
|
override val CachedFileInfo.hasEffect get() = jsIrHeader.importedWithEffectInModuleWithName != null
|
||||||
}
|
override val CachedFileInfo.hasExport get() = this is CachedFileInfo.MainFileCachedInfo && exportFileCachedInfo != null
|
||||||
val fetchedProxyFileInfo = moduleArtifact.fetchModuleProxyFileInfo()?.takeIf {
|
|
||||||
it.jsIrHeader.importedWithEffectInModuleWithName == importWithEffectIn
|
override fun SrcFileArtifact.generateArtifact(module: ModuleArtifact) = when {
|
||||||
}
|
isModified() -> module.loadFileInfoFor(this)
|
||||||
list.plus(fetchedProxyFileInfo ?: moduleArtifact.generateModuleProxyFileCachedInfo(importWithEffectIn))
|
else -> module.fetchFileInfoFor(this) ?: module.loadFileInfoFor(this)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun List<CachedFileInfo>.merge() = when (size) {
|
||||||
|
0 -> error("Can't merge empty list of MainFileCachedInfo")
|
||||||
|
1 -> first()
|
||||||
|
else -> CachedFileInfo.MainFileCachedInfo.Merged(map { it as CachedFileInfo.MainFileCachedInfo })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ModuleArtifact.generateArtifact(moduleNameForEffects: String?) =
|
||||||
|
fetchModuleProxyFileInfo()?.takeIf {
|
||||||
|
it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects
|
||||||
|
} ?: generateModuleProxyFileCachedInfo(moduleNameForEffects)
|
||||||
|
}
|
||||||
|
|
||||||
|
return perFileGenerator.generatePerFileArtifacts(moduleArtifacts)
|
||||||
|
.flatMap { if (it is CachedFileInfo.MainFileCachedInfo) listOfNotNull(it.exportFileCachedInfo, it) else listOf(it) }
|
||||||
.onEach { headerToCachedInfo[it.jsIrHeader] = it }
|
.onEach { headerToCachedInfo[it.jsIrHeader] = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,9 +358,8 @@ class JsPerFileCache(private val moduleArtifacts: List<ModuleArtifact>) : JsMult
|
|||||||
}
|
}
|
||||||
|
|
||||||
private data class CachedFileArtifacts(val jsCodeFile: File, val sourceMapFile: File?, val tsDeclarationsFile: File?)
|
private data class CachedFileArtifacts(val jsCodeFile: File, val sourceMapFile: File?, val tsDeclarationsFile: File?)
|
||||||
private data class LoadedJsIrModuleHeaders(val mainHeader: JsIrModuleHeader, val exportHeader: JsIrModuleHeader?)
|
private data class LoadedJsIrModuleHeaders(val mainHeader: JsIrModuleHeader, val exportHeader: JsIrModuleHeader?) {
|
||||||
|
fun toPair() = mainHeader to exportHeader
|
||||||
|
}
|
||||||
|
|
||||||
private fun List<JsPerFileCache.CachedFileInfo>.hasExportFile(): Boolean = size > 1
|
|
||||||
private fun List<JsPerFileCache.CachedFileInfo>.hasModuleLevelEffect(): Boolean =
|
|
||||||
last().jsIrHeader.importedWithEffectInModuleWithName != null
|
|
||||||
}
|
}
|
||||||
@@ -6,22 +6,20 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModule
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModule
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.deserializeJsIrProgramFragment
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.deserializeJsIrProgramFragment
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SrcFileArtifact(val srcFilePath: String, private val fragments: List<JsIrProgramFragment>, private val astArtifact: File? = null) {
|
class SrcFileArtifact(val srcFilePath: String, private val fragments: JsIrProgramFragments?, private val astArtifact: File? = null) {
|
||||||
fun loadJsIrFragments(): List<JsIrProgramFragment> {
|
fun loadJsIrFragments(): JsIrProgramFragments? {
|
||||||
if (fragments.isNotEmpty()) {
|
if (fragments != null) {
|
||||||
return fragments
|
return fragments
|
||||||
}
|
}
|
||||||
return astArtifact?.ifExists { readBytes() }?.let {
|
return astArtifact?.ifExists { readBytes() }?.let { deserializeJsIrProgramFragment(it) }
|
||||||
deserializeJsIrProgramFragment(it)
|
|
||||||
} ?: emptyList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isModified() = fragments.isNotEmpty()
|
fun isModified() = fragments != null
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModuleArtifact(
|
class ModuleArtifact(
|
||||||
@@ -35,7 +33,10 @@ class ModuleArtifact(
|
|||||||
val moduleExternalName = externalModuleName ?: moduleSafeName
|
val moduleExternalName = externalModuleName ?: moduleSafeName
|
||||||
|
|
||||||
fun loadJsIrModule(): JsIrModule {
|
fun loadJsIrModule(): JsIrModule {
|
||||||
val fragments = fileArtifacts.sortedBy { it.srcFilePath }.flatMap { it.loadJsIrFragments() }
|
val fragments = fileArtifacts.sortedBy { it.srcFilePath }.flatMap {
|
||||||
|
val fragments = it.loadJsIrFragments()
|
||||||
|
listOfNotNull(fragments?.mainFragment, fragments?.exportFragment)
|
||||||
|
}
|
||||||
return JsIrModule(moduleSafeName, moduleExternalName, fragments)
|
return JsIrModule(moduleSafeName, moduleExternalName, fragments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-38
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
|
|||||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||||
|
import org.jetbrains.kotlin.utils.putToMultiMap
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -145,7 +146,6 @@ class IrModuleToJsTransformer(
|
|||||||
val file: IrFile,
|
val file: IrFile,
|
||||||
val exports: List<ExportedDeclaration>,
|
val exports: List<ExportedDeclaration>,
|
||||||
val tsDeclarations: TypeScriptFragment?,
|
val tsDeclarations: TypeScriptFragment?,
|
||||||
val generatedFrom: IrFile? = null
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List<IrFileExports>)
|
private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List<IrFileExports>)
|
||||||
@@ -208,19 +208,14 @@ class IrModuleToJsTransformer(
|
|||||||
fun makeIrFragmentsGenerators(
|
fun makeIrFragmentsGenerators(
|
||||||
dirtyFiles: Collection<IrFile>,
|
dirtyFiles: Collection<IrFile>,
|
||||||
allModules: Collection<IrModuleFragment>
|
allModules: Collection<IrModuleFragment>
|
||||||
): List<() -> List<JsIrProgramFragment>> {
|
): List<() -> JsIrProgramFragments> {
|
||||||
val files = dirtyFiles + backendContext.mapping.chunkToOriginalFile.keys
|
|
||||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules)
|
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules)
|
||||||
val exportData = exportModelGenerator.generateExportWithExternals(files)
|
val exportData = exportModelGenerator.generateExportWithExternals(dirtyFiles)
|
||||||
val mode = TranslationMode.fromFlags(production = false, backendContext.granularity, minimizedMemberNames = false)
|
val mode = TranslationMode.fromFlags(production = false, backendContext.granularity, minimizedMemberNames = false)
|
||||||
|
|
||||||
doStaticMembersLowering(allModules)
|
doStaticMembersLowering(allModules)
|
||||||
|
|
||||||
return exportData
|
return exportData.map { { generateProgramFragment(it, mode) } }
|
||||||
.groupBy { it.generatedFrom ?: it.file }
|
|
||||||
.map {
|
|
||||||
{ it.value.flatMap { generateProgramFragment(it, mode) } }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExportModelGenerator.generateExportWithExternals(irFiles: Collection<IrFile>): List<IrFileExports> {
|
private fun ExportModelGenerator.generateExportWithExternals(irFiles: Collection<IrFile>): List<IrFileExports> {
|
||||||
@@ -231,7 +226,7 @@ class IrModuleToJsTransformer(
|
|||||||
val tsDeclarations = runIf(shouldGenerateTypeScriptDefinitions) {
|
val tsDeclarations = runIf(shouldGenerateTypeScriptDefinitions) {
|
||||||
allExports.ifNotEmpty { toTypeScriptFragment(moduleKind) }
|
allExports.ifNotEmpty { toTypeScriptFragment(moduleKind) }
|
||||||
}
|
}
|
||||||
IrFileExports(irFile, allExports, tsDeclarations, context.mapping.chunkToOriginalFile[irFile])
|
IrFileExports(irFile, allExports, tsDeclarations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +252,10 @@ class IrModuleToJsTransformer(
|
|||||||
JsIrModule(
|
JsIrModule(
|
||||||
data.fragment.safeName,
|
data.fragment.safeName,
|
||||||
moduleFragmentToNameMapper.getExternalNameFor(data.fragment),
|
moduleFragmentToNameMapper.getExternalNameFor(data.fragment),
|
||||||
data.files.flatMap { generateProgramFragment(it, mode) },
|
data.files.flatMap {
|
||||||
|
val fragments = generateProgramFragment(it, mode)
|
||||||
|
listOfNotNull(fragments.mainFragment, fragments.exportFragment)
|
||||||
|
},
|
||||||
mainModule.fragment.safeName.takeIf { !isEsModules && data != mainModule }
|
mainModule.fragment.safeName.takeIf { !isEsModules && data != mainModule }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -266,40 +264,40 @@ class IrModuleToJsTransformer(
|
|||||||
|
|
||||||
private fun generateJsIrProgramPerFile(exportData: List<IrAndExportedDeclarations>, mode: TranslationMode): JsIrProgram {
|
private fun generateJsIrProgramPerFile(exportData: List<IrAndExportedDeclarations>, mode: TranslationMode): JsIrProgram {
|
||||||
val mainModule = exportData.last()
|
val mainModule = exportData.last()
|
||||||
var someModuleHasEffect = false
|
|
||||||
|
|
||||||
val modulesPerFile = buildList {
|
val perFileGenerator = object : PerFileGenerator<IrAndExportedDeclarations, IrFileExports, JsIrModules> {
|
||||||
for (module in exportData) {
|
override val mainModuleName get() = mainModule.fragment.safeName
|
||||||
var hasModuleLevelEffect = false
|
|
||||||
var hasFileWithJsExportedDeclaration = false
|
|
||||||
|
|
||||||
for (fileExports in module.files) {
|
override val IrAndExportedDeclarations.isMain get() = this === mainModule
|
||||||
if (fileExports.file.couldBeSkipped()) continue
|
override val IrAndExportedDeclarations.fileList get() = files
|
||||||
val programFragments = generateProgramFragment(fileExports, mode)
|
|
||||||
|
|
||||||
fileExports.toJsIrModule(module, programFragments.mainFragment).let {
|
override val JsIrModules.artifactName get() = this.mainModule.externalModuleName
|
||||||
add(it)
|
override val JsIrModules.hasEffect get() = this.mainModule.importedWithEffectInModuleWithName != null
|
||||||
if (it.importedWithEffectInModuleWithName != null) {
|
override val JsIrModules.hasExport get() = this.exportModule != null
|
||||||
someModuleHasEffect = true
|
|
||||||
hasModuleLevelEffect = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
programFragments.exportFragment?.let {
|
override fun List<JsIrModules>.merge() =
|
||||||
add(fileExports.toJsIrModuleForExport(module, it))
|
JsIrModules(map { it.mainModule }.merge(), mapNotNull { it.exportModule }.ifNotEmpty { merge() })
|
||||||
hasFileWithJsExportedDeclaration = true
|
|
||||||
}
|
override fun IrAndExportedDeclarations.generateArtifact(moduleNameForEffects: String?) =
|
||||||
|
JsIrModules(toJsIrProxyModule(moduleNameForEffects))
|
||||||
|
|
||||||
|
override fun IrFileExports.generateArtifact(module: IrAndExportedDeclarations) = takeIf { !file.couldBeSkipped() }
|
||||||
|
?.let { generateProgramFragment(it, mode) }
|
||||||
|
?.let {
|
||||||
|
JsIrModules(
|
||||||
|
toJsIrModule(module, it.mainFragment),
|
||||||
|
it.exportFragment?.run { toJsIrModuleForExport(module, this) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFileWithJsExportedDeclaration || hasModuleLevelEffect || (module === mainModule && someModuleHasEffect)) {
|
|
||||||
add(module.toJsIrProxyModule(mainModule.fragment.safeName.takeIf { module !== mainModule && hasModuleLevelEffect }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsIrProgram(modulesPerFile)
|
return JsIrProgram(perFileGenerator.generatePerFileArtifacts(exportData).flatMap {
|
||||||
|
listOfNotNull(it.mainModule, it.exportModule)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class JsIrModules(val mainModule: JsIrModule, val exportModule: JsIrModule? = null)
|
||||||
|
|
||||||
private fun IrFileExports.toJsIrModule(module: IrAndExportedDeclarations, programFragment: JsIrProgramFragment): JsIrModule {
|
private fun IrFileExports.toJsIrModule(module: IrAndExportedDeclarations, programFragment: JsIrProgramFragment): JsIrModule {
|
||||||
return JsIrModule(
|
return JsIrModule(
|
||||||
moduleFragmentToNameMapper.getSafeNameFor(file),
|
moduleFragmentToNameMapper.getSafeNameFor(file),
|
||||||
@@ -350,7 +348,7 @@ class IrModuleToJsTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateProgramFragment(fileExports: IrFileExports, mode: TranslationMode): List<JsIrProgramFragment> {
|
private fun generateProgramFragment(fileExports: IrFileExports, mode: TranslationMode): JsIrProgramFragments {
|
||||||
val globalNameScope = NameTable<IrDeclaration>()
|
val globalNameScope = NameTable<IrDeclaration>()
|
||||||
val nameGenerator = JsNameLinkingNamer(backendContext, mode.minimizedMemberNames, isEsModules)
|
val nameGenerator = JsNameLinkingNamer(backendContext, mode.minimizedMemberNames, isEsModules)
|
||||||
val staticContext = JsStaticContext(backendContext, nameGenerator, globalNameScope, mode)
|
val staticContext = JsStaticContext(backendContext, nameGenerator, globalNameScope, mode)
|
||||||
@@ -432,7 +430,7 @@ class IrModuleToJsTransformer(
|
|||||||
optimizeFragmentByJsAst(result)
|
optimizeFragmentByJsAst(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
return listOfNotNull(result, exportFragment)
|
return JsIrProgramFragments(result, exportFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Set<IrDeclaration>.computeTag(declaration: IrDeclaration): String? {
|
private fun Set<IrDeclaration>.computeTag(declaration: IrDeclaration): String? {
|
||||||
|
|||||||
+2
-2
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
|
||||||
|
class JsIrProgramFragments(val mainFragment: JsIrProgramFragment, val exportFragment: JsIrProgramFragment? = null)
|
||||||
|
|
||||||
class JsIrProgramFragment(val name: String, val packageFqn: String) {
|
class JsIrProgramFragment(val name: String, val packageFqn: String) {
|
||||||
val nameBindings = mutableMapOf<String, JsName>()
|
val nameBindings = mutableMapOf<String, JsName>()
|
||||||
val optionalCrossModuleImports = hashSetOf<String>()
|
val optionalCrossModuleImports = hashSetOf<String>()
|
||||||
@@ -303,6 +305,4 @@ fun JsStatement.renameImportedSymbolInternalName(newName: JsName): JsStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val List<JsIrProgramFragment>.mainFragment: JsIrProgramFragment get() = first()
|
|
||||||
val List<JsIrProgramFragment>.exportFragment: JsIrProgramFragment? get() = getOrNull(1)
|
|
||||||
val JsIrProgramFragment.hasEffect: Boolean get() = eagerInitializers.statements.isNotEmpty()
|
val JsIrProgramFragment.hasEffect: Boolean get() = eagerInitializers.statements.isNotEmpty()
|
||||||
+54
@@ -364,3 +364,57 @@ class Merger(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<JsIrModule>.merge(): JsIrModule {
|
||||||
|
assert(isNotEmpty()) { "Can't merge empty list of modules" }
|
||||||
|
val firstModule = first()
|
||||||
|
|
||||||
|
return if (size == 1) {
|
||||||
|
firstModule
|
||||||
|
} else {
|
||||||
|
val fragments = mutableListOf<JsIrProgramFragment>()
|
||||||
|
var reexportedInModuleWithName: String? = null
|
||||||
|
|
||||||
|
for (module in this) {
|
||||||
|
fragments.addAll(module.fragments)
|
||||||
|
module.reexportedInModuleWithName?.let { reexportedInModuleWithName = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
JsIrModule(firstModule.moduleName, firstModule.externalModuleName, fragments, reexportedInModuleWithName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<JsIrModuleHeader>.merge(): JsIrModuleHeader {
|
||||||
|
assert(isNotEmpty()) { "Can't merge empty list of module headers" }
|
||||||
|
val firstModule = first()
|
||||||
|
|
||||||
|
return if (size == 1) {
|
||||||
|
firstModule
|
||||||
|
} else {
|
||||||
|
val definitions = mutableSetOf<String>()
|
||||||
|
val nameBindings = mutableMapOf<String, String>()
|
||||||
|
val optionalCrossModuleImports = mutableSetOf<String>()
|
||||||
|
var reexportedInModuleWithName: String? = null
|
||||||
|
var importedWithEffectInModuleWithName: String? = null
|
||||||
|
|
||||||
|
for (header in this) {
|
||||||
|
definitions.addAll(header.definitions)
|
||||||
|
nameBindings.putAll(header.nameBindings)
|
||||||
|
optionalCrossModuleImports.addAll(header.optionalCrossModuleImports)
|
||||||
|
|
||||||
|
header.reexportedInModuleWithName?.let { reexportedInModuleWithName = it }
|
||||||
|
header.importedWithEffectInModuleWithName?.let { importedWithEffectInModuleWithName = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
JsIrModuleHeader(
|
||||||
|
firstModule.moduleName,
|
||||||
|
firstModule.externalModuleName,
|
||||||
|
definitions,
|
||||||
|
nameBindings,
|
||||||
|
optionalCrossModuleImports,
|
||||||
|
reexportedInModuleWithName,
|
||||||
|
importedWithEffectInModuleWithName,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-18
@@ -6,33 +6,16 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsFileName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsFileName
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.nameWithoutExtension
|
import org.jetbrains.kotlin.ir.backend.js.utils.nameWithoutExtension
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.path
|
|
||||||
|
|
||||||
private const val EXPORTER_FILE_POSTFIX = ".export"
|
private const val EXPORTER_FILE_POSTFIX = ".export"
|
||||||
|
|
||||||
class ModuleFragmentToExternalName(private val jsOutputNamesMapping: Map<IrModuleFragment, String>) {
|
class ModuleFragmentToExternalName(private val jsOutputNamesMapping: Map<IrModuleFragment, String>) {
|
||||||
private val externalNameToItsFile = hashMapOf<String, IrFile>()
|
|
||||||
|
|
||||||
fun getExternalNameFor(file: IrFile): String {
|
fun getExternalNameFor(file: IrFile): String {
|
||||||
return getExternalNameFor(file.outputName, file.packageFqName.asString(), file.module.getJsOutputName()).also {
|
return getExternalNameFor(file.outputName, file.packageFqName.asString(), file.module.getJsOutputName())
|
||||||
val alreadyReservedBy = externalNameToItsFile.putIfAbsent(it.lowercase(), file)
|
|
||||||
|
|
||||||
if (alreadyReservedBy != null && alreadyReservedBy != file) {
|
|
||||||
error(
|
|
||||||
"""
|
|
||||||
|There are two files in module '${file.module.name}' that have the similar package and file names.
|
|
||||||
| - Package "${file.packageFqName.asString()}" and path "${file.path}"
|
|
||||||
| - Package "${alreadyReservedBy.packageFqName.asString()}" and path "${alreadyReservedBy.path}"
|
|
||||||
|Note, that if the difference is only in letter cases, it also could lead to a clash of the compiled artifacts
|
|
||||||
""".trimMargin()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getExternalNameFor(fileName: String, packageFqn: String, moduleName: String): String {
|
fun getExternalNameFor(fileName: String, packageFqn: String, moduleName: String): String {
|
||||||
|
|||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.utils.putToMultiMap
|
||||||
|
|
||||||
|
interface PerFileGenerator<Module, File, Artifact> {
|
||||||
|
val mainModuleName: String
|
||||||
|
|
||||||
|
val Module.isMain: Boolean
|
||||||
|
val Module.fileList: Iterable<File>
|
||||||
|
|
||||||
|
val Artifact.artifactName: String
|
||||||
|
val Artifact.hasEffect: Boolean
|
||||||
|
val Artifact.hasExport: Boolean
|
||||||
|
|
||||||
|
fun List<Artifact>.merge(): Artifact
|
||||||
|
fun File.generateArtifact(module: Module): Artifact?
|
||||||
|
fun Module.generateArtifact(moduleNameForEffects: String?): Artifact
|
||||||
|
|
||||||
|
fun generatePerFileArtifacts(modules: List<Module>): List<Artifact> {
|
||||||
|
var someModuleHasEffect = false
|
||||||
|
|
||||||
|
val nameToModulePerFile = buildMap {
|
||||||
|
for (module in modules) {
|
||||||
|
var hasModuleLevelEffect = false
|
||||||
|
var hasFileWithExportedDeclaration = false
|
||||||
|
|
||||||
|
for (file in module.fileList) {
|
||||||
|
val generatedArtifact = file.generateArtifact(module) ?: continue
|
||||||
|
|
||||||
|
if (generatedArtifact.hasExport) {
|
||||||
|
hasFileWithExportedDeclaration = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generatedArtifact.hasEffect) {
|
||||||
|
hasModuleLevelEffect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
putToMultiMap(generatedArtifact.artifactName, generatedArtifact)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasModuleLevelEffect) {
|
||||||
|
someModuleHasEffect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFileWithExportedDeclaration || hasModuleLevelEffect || (module.isMain && someModuleHasEffect)) {
|
||||||
|
val proxyArtifact =
|
||||||
|
module.generateArtifact(mainModuleName.takeIf { !module.isMain && hasModuleLevelEffect }) ?: continue
|
||||||
|
putToMultiMap(proxyArtifact.artifactName, proxyArtifact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameToModulePerFile.values.map { it.merge() }
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-3
@@ -8,13 +8,14 @@ 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.export.TypeScriptFragment
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrIcClassModel
|
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.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun deserializeJsIrProgramFragment(input: ByteArray): List<JsIrProgramFragment> {
|
fun deserializeJsIrProgramFragment(input: ByteArray): JsIrProgramFragments {
|
||||||
return JsIrAstDeserializer(input).readFragments()
|
return JsIrAstDeserializer(input).readFragments()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +77,8 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
return if (readBoolean()) then() else null
|
return if (readBoolean()) then() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFragments(): List<JsIrProgramFragment> {
|
fun readFragments(): JsIrProgramFragments {
|
||||||
return readList { readFragment() }
|
return JsIrProgramFragments(readFragment(), ifTrue { readFragment() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFragment(): JsIrProgramFragment {
|
fun readFragment(): JsIrProgramFragment {
|
||||||
|
|||||||
+6
-5
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrIcClassModel
|
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.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -15,8 +16,8 @@ import java.io.DataOutputStream
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun List<JsIrProgramFragment>.serializeTo(output: OutputStream) {
|
fun JsIrProgramFragments.serializeTo(output: OutputStream) {
|
||||||
JsIrAstSerializer().appendAll(this).saveTo(output)
|
JsIrAstSerializer().append(this).saveTo(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DataWriter {
|
private class DataWriter {
|
||||||
@@ -89,9 +90,9 @@ private class JsIrAstSerializer {
|
|||||||
private val fileStack: Deque<String> = ArrayDeque()
|
private val fileStack: Deque<String> = ArrayDeque()
|
||||||
private val importedNames = mutableSetOf<JsName>()
|
private val importedNames = mutableSetOf<JsName>()
|
||||||
|
|
||||||
fun appendAll(fragments: List<JsIrProgramFragment>): JsIrAstSerializer {
|
fun append(fragments: JsIrProgramFragments): JsIrAstSerializer {
|
||||||
fragmentSerializer.writeInt(fragments.size)
|
append(fragments.mainFragment)
|
||||||
fragments.forEach(::append)
|
fragmentSerializer.ifNotNull(fragments.exportFragment, ::append)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// TARGET_BACKEND: JS_IR
|
// TARGET_BACKEND: JS_IR
|
||||||
// K2 JS_IR MUTE_REASON: java.lang.NullPointerException at org.jetbrains.kotlin.fir.backend.Fir2IrClassifierStorage.getIrClassSymbol
|
|
||||||
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
|
|
||||||
|
|
||||||
// Test that if we have two different files with the same name in the same package, KT-54028 doesn't reproduce.
|
// Test that if we have two different files with the same name in the same package, KT-54028 doesn't reproduce.
|
||||||
|
|
||||||
|
|||||||
+16
-9
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.test.directives.model.singleValue
|
|||||||
import org.jetbrains.kotlin.test.getAnalyzerServices
|
import org.jetbrains.kotlin.test.getAnalyzerServices
|
||||||
import org.jetbrains.kotlin.test.model.FrontendFacade
|
import org.jetbrains.kotlin.test.model.FrontendFacade
|
||||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||||
|
import org.jetbrains.kotlin.test.model.TestFile
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.runners.lightTreeSyntaxDiagnosticsReporterHolder
|
import org.jetbrains.kotlin.test.runners.lightTreeSyntaxDiagnosticsReporterHolder
|
||||||
import org.jetbrains.kotlin.test.services.*
|
import org.jetbrains.kotlin.test.services.*
|
||||||
@@ -282,9 +283,9 @@ open class FirFrontendFacade(
|
|||||||
|
|
||||||
val (ktFiles, lightTreeFiles) = when (parser) {
|
val (ktFiles, lightTreeFiles) = when (parser) {
|
||||||
FirParser.LightTree -> {
|
FirParser.LightTree -> {
|
||||||
emptyList<KtFile>() to testServices.sourceFileProvider.getKtSourceFilesForSourceFiles(module.files).values
|
emptyMap<TestFile, KtFile>() to testServices.sourceFileProvider.getKtSourceFilesForSourceFiles(module.files)
|
||||||
}
|
}
|
||||||
FirParser.Psi -> testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList()
|
FirParser.Psi -> testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project) to emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
|
val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
|
||||||
@@ -304,21 +305,27 @@ open class FirFrontendFacade(
|
|||||||
sessionConfigurator,
|
sessionConfigurator,
|
||||||
predefinedJavaComponents,
|
predefinedJavaComponents,
|
||||||
project,
|
project,
|
||||||
ktFiles
|
ktFiles.values
|
||||||
)
|
)
|
||||||
|
|
||||||
val firAnalyzerFacade = FirAnalyzerFacade(
|
val firAnalyzerFacade = FirAnalyzerFacade(
|
||||||
moduleBasedSession,
|
moduleBasedSession,
|
||||||
ktFiles,
|
ktFiles.values,
|
||||||
lightTreeFiles,
|
lightTreeFiles.values,
|
||||||
parser,
|
parser,
|
||||||
testServices.lightTreeSyntaxDiagnosticsReporterHolder?.reporter,
|
testServices.lightTreeSyntaxDiagnosticsReporterHolder?.reporter,
|
||||||
)
|
)
|
||||||
val firFiles = firAnalyzerFacade.runResolution()
|
val firFiles = firAnalyzerFacade.runResolution()
|
||||||
val filesMap = firFiles.mapNotNull { firFile ->
|
|
||||||
val testFile = module.files.firstOrNull { it.name == firFile.name } ?: return@mapNotNull null
|
val usedFilesMap = when (parser) {
|
||||||
testFile to firFile
|
FirParser.LightTree -> lightTreeFiles
|
||||||
}.toMap()
|
FirParser.Psi -> ktFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
val filesMap = usedFilesMap.keys
|
||||||
|
.zip(firFiles)
|
||||||
|
.onEach { assert(it.first.name == it.second.name) }
|
||||||
|
.toMap()
|
||||||
|
|
||||||
return FirOutputPartForDependsOnModule(module, moduleBasedSession, firAnalyzerFacade, filesMap)
|
return FirOutputPartForDependsOnModule(module, moduleBasedSession, firAnalyzerFacade, filesMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,3 +75,8 @@ fun <T> Collection<T>.atMostOne(): T? {
|
|||||||
* If there are more such elements, throws an exception.
|
* If there are more such elements, throws an exception.
|
||||||
*/
|
*/
|
||||||
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
|
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
|
||||||
|
|
||||||
|
fun <K, V> MutableMap<K, MutableList<V>>.putToMultiMap(key: K, value: V) {
|
||||||
|
val list = getOrPut(key) { mutableListOf() }
|
||||||
|
list.add(value)
|
||||||
|
}
|
||||||
|
|||||||
Generated
+6
@@ -175,6 +175,12 @@ public class JsFirInvalidationPerFileTestGenerated extends AbstractJsFirInvalida
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
Generated
+6
@@ -175,6 +175,12 @@ public class JsFirInvalidationPerModuleTestGenerated extends AbstractJsFirInvali
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
Generated
+6
@@ -175,6 +175,12 @@ public class JsIrES6InvalidationPerFileTestGenerated extends AbstractJsIrES6Inva
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
+6
@@ -175,6 +175,12 @@ public class JsIrES6InvalidationPerModuleTestGenerated extends AbstractJsIrES6In
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
Generated
+6
@@ -175,6 +175,12 @@ public class JsIrInvalidationPerFileTestGenerated extends AbstractJsIrInvalidati
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
Generated
+6
@@ -175,6 +175,12 @@ public class JsIrInvalidationPerModuleTestGenerated extends AbstractJsIrInvalida
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("friendDependency")
|
@TestMetadata("friendDependency")
|
||||||
public void testFriendDependency() throws Exception {
|
public void testFriendDependency() throws Exception {
|
||||||
|
|||||||
+6
@@ -2349,6 +2349,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
|||||||
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash.kt")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/esModules/export/fileNameClash.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
|
|||||||
+6
@@ -2455,6 +2455,12 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest {
|
|||||||
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash.kt")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/esModules/export/fileNameClash.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
|
|||||||
+6
@@ -2455,6 +2455,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
|||||||
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash.kt")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/esModules/export/fileNameClash.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
|
|||||||
+6
@@ -2349,6 +2349,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fileNameClash.kt")
|
||||||
|
public void testFileNameClash() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/esModules/export/fileNameClash.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
|
// ES_MODULES
|
||||||
|
|
||||||
|
// MODULE: name_clash
|
||||||
|
// FILE: test1/lib.kt
|
||||||
|
package foo
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
open class A<T> {
|
||||||
|
open fun foo(value: T): T = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test2/lib.kt
|
||||||
|
package foo
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class B: A<String>() {
|
||||||
|
override fun foo(value: String): String = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: entry.mjs
|
||||||
|
// ENTRY_ES_MODULE
|
||||||
|
import { A, B } from "./fileNameClash-name_clash_v5.mjs";
|
||||||
|
|
||||||
|
export function box() {
|
||||||
|
var a = new A()
|
||||||
|
var aFoo = a.foo("ok")
|
||||||
|
if (aFoo != "ok") return "fail 1"
|
||||||
|
|
||||||
|
var b = new B()
|
||||||
|
var bFoo = b.foo("ok")
|
||||||
|
if (bFoo != "ok") return "fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun test1() = test2()
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun test1() = test2()
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun test1() = "OK"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@file:JsFileName("f1")
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
fun test2() = "OK"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@file:JsFileName("f1")
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun test2() = "OK"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun test2() = "OK"
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
STEP 0:
|
||||||
|
added file: f1.kt
|
||||||
|
STEP 1:
|
||||||
|
modifications:
|
||||||
|
U : f1.1.kt -> f1.kt
|
||||||
|
U : f2.1.kt -> f2.kt
|
||||||
|
modified ir: f1.kt
|
||||||
|
added file: f2.kt
|
||||||
|
STEP 2:
|
||||||
|
modifications:
|
||||||
|
U : f2.2.kt -> f2.kt
|
||||||
|
modified ir: f2.kt
|
||||||
|
updated imports: f1.kt
|
||||||
|
STEP 3:
|
||||||
|
modifications:
|
||||||
|
U : f1.3.kt -> f1.kt
|
||||||
|
modified ir: f1.kt
|
||||||
|
STEP 4:
|
||||||
|
modifications:
|
||||||
|
U : f2.4.kt -> f2.kt
|
||||||
|
modified ir: f2.kt
|
||||||
|
updated imports: f1.kt
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import foo.test1
|
||||||
|
|
||||||
|
fun box() = test1()
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
STEP 0:
|
||||||
|
dependencies: lib
|
||||||
|
added file: m.kt
|
||||||
|
STEP 1:
|
||||||
|
dependencies: lib
|
||||||
|
STEP 2:
|
||||||
|
dependencies: lib
|
||||||
|
STEP 3:
|
||||||
|
dependencies: lib
|
||||||
|
updated imports: m.kt
|
||||||
|
STEP 4:
|
||||||
|
dependencies: lib
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
MODULES: lib, main
|
||||||
|
|
||||||
|
STEP 0:
|
||||||
|
libs: lib, main
|
||||||
|
dirty js modules: main, lib
|
||||||
|
dirty js files: lib/foo/f1, main/m, main/m.export, main
|
||||||
|
STEP 1:
|
||||||
|
libs: lib, main
|
||||||
|
dirty js modules: lib
|
||||||
|
dirty js files: lib/foo/f1
|
||||||
|
STEP 2:
|
||||||
|
libs: lib, main
|
||||||
|
dirty js modules: lib
|
||||||
|
dirty js files: lib/foo/f1, lib/foo/f1.export, lib
|
||||||
|
STEP 3:
|
||||||
|
libs: lib, main
|
||||||
|
dirty js modules: lib, main
|
||||||
|
dirty js files: lib/foo/f1, lib/foo/f1.export, main/m
|
||||||
|
STEP 4:
|
||||||
|
libs: lib, main
|
||||||
|
dirty js modules: lib
|
||||||
|
dirty js files: lib/foo/f1, lib/foo/f2, lib/foo/f1.export
|
||||||
-21
@@ -372,27 +372,6 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("per-file with the declarations validation")
|
|
||||||
@GradleTest
|
|
||||||
fun testPerFileProjectWithResultFilesClash(gradleVersion: GradleVersion) {
|
|
||||||
project("kotlin-js-invalid-per-file-project", gradleVersion) {
|
|
||||||
buildAndFail("compileDevelopmentExecutableKotlinJs") {
|
|
||||||
assertTasksFailed(":compileDevelopmentExecutableKotlinJs")
|
|
||||||
assertOutputContains("""
|
|
||||||
|There are two files in module '<kotlin-js-invalid-per-file-project>' that have the similar package and file names.
|
|
||||||
| - Package "com.example" and
|
|
||||||
""".trimMargin())
|
|
||||||
}
|
|
||||||
buildAndFail("compileProductionExecutableKotlinJs") {
|
|
||||||
assertTasksFailed(":compileProductionExecutableKotlinJs")
|
|
||||||
assertOutputContains("""
|
|
||||||
|There are two files in module '<kotlin-js-invalid-per-file-project>' that have the similar package and file names.
|
|
||||||
| - Package "com.example" and path
|
|
||||||
""".trimMargin())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("fully qualified names can be used in the sourcemap")
|
@DisplayName("fully qualified names can be used in the sourcemap")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
fun testKotlinJsSourceMapGenerateFqNames(gradleVersion: GradleVersion) {
|
fun testKotlinJsSourceMapGenerateFqNames(gradleVersion: GradleVersion) {
|
||||||
|
|||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
plugins {
|
|
||||||
kotlin("js")
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
js(IR) {
|
|
||||||
useEsModules()
|
|
||||||
binaries.executable()
|
|
||||||
nodejs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-8
@@ -1,8 +0,0 @@
|
|||||||
kotlin.tests.individualTaskReports=true
|
|
||||||
kotlin.js.ir.output.granularity=per-file
|
|
||||||
kotlin.incremental=false
|
|
||||||
kotlin.incremental.js=false
|
|
||||||
kotlin.incremental.js.ir=false
|
|
||||||
kotlin.incremental.js.klib=false
|
|
||||||
kotlin.incremental.multiplatform=false
|
|
||||||
kotlin.incremental.useClasspathSnapshot=false
|
|
||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example
|
|
||||||
|
|
||||||
@JsExport
|
|
||||||
fun best(): Int {
|
|
||||||
return 42
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsExport
|
|
||||||
fun simpleBest(): Int {
|
|
||||||
return 73
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example
|
|
||||||
|
|
||||||
@JsExport
|
|
||||||
public val foo = 44
|
|
||||||
Reference in New Issue
Block a user