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 76eb293e083..a6ef11e50ef 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 @@ -72,6 +72,13 @@ private val K2JSCompilerArguments.granularity: JsGenerationGranularity else -> JsGenerationGranularity.WHOLE_PROGRAM } +private val K2JSCompilerArguments.dtsStrategy: TsCompilationStrategy + get() = when { + !this.generateDts -> TsCompilationStrategy.NONE + this.irPerFile -> TsCompilationStrategy.EACH_FILE + else -> TsCompilationStrategy.MERGED + } + private class DisposableZipFileSystemAccessor private constructor( private val zipAccessor: ZipFileSystemCacheableAccessor ) : Disposable, ZipFileSystemAccessor by zipAccessor { @@ -100,6 +107,7 @@ class K2JsIrCompiler : CLICompiler() { ) { private fun lowerIr(): LoweredIr { return compile( + mainCallArguments, module, phaseConfig, IrFactoryImplForJsIC(WholeWorldStageController()), @@ -122,7 +130,7 @@ class K2JsIrCompiler : CLICompiler() { private fun makeJsCodeGenerator(): JsCodeGenerator { val ir = lowerIr() - val transformer = IrModuleToJsTransformer(ir.context, mainCallArguments, ir.moduleFragmentToUniqueName) + val transformer = IrModuleToJsTransformer(ir.context, ir.moduleFragmentToUniqueName, mainCallArguments != null) val mode = TranslationMode.fromFlags(arguments.irDce, arguments.granularity, arguments.irMinimizedMemberNames) return transformer.makeJsCodeGenerator(ir.allModules, mode) @@ -303,7 +311,7 @@ class K2JsIrCompiler : CLICompiler() { ) val (outputs, rebuiltModules) = jsExecutableProducer.buildExecutable(arguments.granularity, outJsProgram = false) - outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) + outputs.writeAll(outputDir, outputName, arguments.dtsStrategy, moduleName, moduleKind) icCaches.cacheGuard.release() @@ -391,7 +399,7 @@ class K2JsIrCompiler : CLICompiler() { messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms") - outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) + outputs.writeAll(outputDir, outputName, arguments.dtsStrategy, moduleName, moduleKind) } catch (e: CompilationException) { messageCollector.report( ERROR, @@ -611,10 +619,10 @@ class K2JsIrCompiler : CLICompiler() { cacheDir = cacheDirectory, compilerConfiguration = configurationJs, irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) }, - mainArguments = mainCallArguments, compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC( mainModule, + mainCallArguments, cfg, arguments.granularity, PhaseConfig(jsPhases), diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 2aea7220a36..c99e762d682 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -62,12 +62,13 @@ class JsIrBackendContext( val additionalExportedDeclarationNames: Set, keep: Set, override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context + val mainCallArguments: List?, val dceRuntimeDiagnostic: RuntimeDiagnostic? = null, val safeExternalBoolean: Boolean = false, val safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null, override val mapping: JsMapping = JsMapping(), val granularity: JsGenerationGranularity = JsGenerationGranularity.WHOLE_PROGRAM, - val incrementalCacheEnabled: Boolean = false + val incrementalCacheEnabled: Boolean = false, ) : JsCommonBackendContext { override val scriptMode: Boolean get() = false diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 0fcf41f97ff..8380f335363 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -863,6 +863,12 @@ val constEvaluationPhase = makeJsModulePhase( description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`", ).toModuleLowering() +val mainFunctionCallWrapperLowering = makeJsModulePhase( + ::MainFunctionCallWrapperLowering, + name = "MainFunctionCallWrapperLowering", + description = "Generate main function call inside the wrapper-function" +).toModuleLowering() + val loweringList = listOf( scriptRemoveReceiverLowering, validateIrBeforeLowering, @@ -968,6 +974,7 @@ val loweringList = listOf( callsLoweringPhase, escapedIdentifiersLowering, implicitlyExportedDeclarationsMarkingLowering, + mainFunctionCallWrapperLowering, cleanupLoweringPhase, // Currently broken due to static members lowering making single-open-class // files non-recognizable as single-class files diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt index bed8335838b..bee8cce355b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsMapping.kt @@ -17,6 +17,8 @@ class JsMapping : DefaultMapping() { val esClassWhichNeedBoxParameters = DefaultDelegateFactory.newDeclarationToValueMapping() val esClassToPossibilityForOptimization = DefaultDelegateFactory.newDeclarationToValueMapping>() + // Main function wrappers + val mainFunctionToItsWrapper = DefaultDelegateFactory.newDeclarationToDeclarationMapping() val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping() val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping() val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping() 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 7f6fa6feea7..c0aa1c05f03 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 @@ -37,6 +37,7 @@ class LoweredIr( ) fun compile( + mainCallArguments: List?, depsDescriptors: ModulesStructure, phaseConfig: PhaseConfig, irFactory: IrFactory, @@ -56,6 +57,7 @@ fun compile( return compileIr( moduleFragment, depsDescriptors.mainModule, + mainCallArguments, depsDescriptors.compilerConfiguration, dependencyModules, moduleToName, @@ -75,6 +77,7 @@ fun compile( fun compileIr( moduleFragment: IrModuleFragment, mainModule: MainModule, + mainCallArguments: List?, configuration: CompilerConfiguration, dependencyModules: List, moduleToName: Map, @@ -109,7 +112,8 @@ fun compileIr( safeExternalBoolean = safeExternalBoolean, safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic, granularity = granularity, - incrementalCacheEnabled = false + incrementalCacheEnabled = false, + mainCallArguments = mainCallArguments ) // Load declarations referenced during `context` initialization diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt index 129afd9f39f..3b54aabc161 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors @OptIn(ObsoleteDescriptorBasedAPI::class) class JsIrCompilerWithIC( private val mainModule: IrModuleFragment, + private val mainArguments: List?, configuration: CompilerConfiguration, granularity: JsGenerationGranularity, private val phaseConfig: PhaseConfig, @@ -42,15 +43,12 @@ class JsIrCompilerWithIC( keep = emptySet(), configuration = configuration, granularity = granularity, - incrementalCacheEnabled = true + incrementalCacheEnabled = true, + mainCallArguments = mainArguments ) } - override fun compile( - allModules: Collection, - dirtyFiles: Collection, - mainArguments: List? - ): List<() -> JsIrProgramFragments> { + override fun compile(allModules: Collection, dirtyFiles: Collection): List<() -> JsIrProgramFragments> { val shouldGeneratePolyfills = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_POLYFILLS) allModules.forEach { @@ -64,7 +62,7 @@ class JsIrCompilerWithIC( lowerPreservingTags(allModules, context, phaseConfig, context.irFactory.stageController as WholeWorldStageController) - val transformer = IrModuleToJsTransformer(context, mainArguments) + val transformer = IrModuleToJsTransformer(context, shouldReferMainFunction = mainArguments != null) return transformer.makeIrFragmentsGenerators(dirtyFiles, allModules) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/Dce.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/Dce.kt index 809920a94ad..845c9fc2831 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/Dce.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/Dce.kt @@ -114,13 +114,9 @@ private fun buildRoots(modules: Iterable, context: JsIrBackend dceRuntimeDiagnostic.unreachableDeclarationMethod(context).owner.acceptVoid(declarationsCollector) } - // TODO: Generate calls to main as IR->IR lowering and reference coroutineEmptyContinuation directly - JsMainFunctionDetector(context).getMainFunctionOrNull(modules.last())?.let { mainFunction -> - add(mainFunction) - if (mainFunction.isLoweredSuspendFunction(context)) { - context.coroutineEmptyContinuation.owner.acceptVoid(declarationsCollector) - } - } + JsMainFunctionDetector(context).getMainFunctionOrNull(modules.last()) + ?.let { context.mapping.mainFunctionToItsWrapper[it] } + ?.let { add(it) } addIfNotNull(context.intrinsics.void.owner.backingField) addAll(context.testFunsPerFile.values) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt index 364e3318864..21adb178211 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.common.serialization.cityHash64String import org.jetbrains.kotlin.config.CompilerConfiguration 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.JsIrProgramFragment import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragments import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.* @@ -30,11 +29,7 @@ import java.nio.file.Files import java.util.EnumSet fun interface JsIrCompilerICInterface { - fun compile( - allModules: Collection, - dirtyFiles: Collection, - mainArguments: List? - ): List<() -> JsIrProgramFragments> + fun compile(allModules: Collection, dirtyFiles: Collection): List<() -> JsIrProgramFragments> } fun interface JsIrCompilerICInterfaceFactory { @@ -62,7 +57,6 @@ class CacheUpdater( cacheDir: String, private val compilerConfiguration: CompilerConfiguration, private val irFactory: () -> IrFactory, - private val mainArguments: List?, private val compilerInterfaceFactory: JsIrCompilerICInterfaceFactory ) { private val stopwatch = StopwatchIC() @@ -646,7 +640,7 @@ class CacheUpdater( } } - val fragmentGenerators = compilerForIC.compile(loadedFragments.values, dirtyFilesForCompiling, mainArguments) + val fragmentGenerators = compilerForIC.compile(loadedFragments.values, dirtyFilesForCompiling) dirtyFilesForRestoring.mapIndexedTo(ArrayList(dirtyFilesForRestoring.size)) { i, libFileAndSrcFile -> Triple(libFileAndSrcFile.first, libFileAndSrcFile.second, fragmentGenerators[i]) @@ -805,6 +799,7 @@ fun rebuildCacheForDirtyFiles( val compilerWithIC = JsIrCompilerWithIC( currentIrModule, + mainArguments, configuration, JsGenerationGranularity.PER_MODULE, PhaseConfig(jsPhases), @@ -815,7 +810,7 @@ fun rebuildCacheForDirtyFiles( loadedIr.loadUnboundSymbols() internationService.clear() - val fragments = compilerWithIC.compile(loadedIr.loadedFragments.values, dirtyIrFiles, mainArguments).memoryOptimizedMap { it() } + val fragments = compilerWithIC.compile(loadedIr.loadedFragments.values, dirtyIrFiles).memoryOptimizedMap { it() } return currentIrModule to dirtyIrFiles.zip(fragments) } 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 4b484a0673f..c7c175092d4 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 @@ -61,9 +61,7 @@ class JsExecutableProducer( stopwatch.startNext("Loading JS IR modules with updated cross module references") jsMultiArtifactCache.loadRequiredJsIrModules(crossModuleReferences) - fun CacheInfo?.compileModule(moduleName: String, generateCallToMain: Boolean): CompilationOutputs { - if (this == null) return jsMultiArtifactCache.fetchCompiledJsCodeForNullCacheInfo() - + fun CacheInfo.compileModule(moduleName: String, isMainModule: Boolean): CompilationOutputs { if (jsIrHeader.associatedModule == null) { stopwatch.startNext("Fetching cached JS code") val compilationOutputs = jsMultiArtifactCache.fetchCompiledJsCode(this) @@ -85,7 +83,7 @@ class JsExecutableProducer( moduleKind = moduleKind, associatedModule.fragments, sourceMapsInfo = sourceMapsInfo, - generateCallToMain = generateCallToMain, + generateCallToMain = isMainModule, crossModuleReferences = crossRef, outJsProgram = outJsProgram ) @@ -95,12 +93,13 @@ class JsExecutableProducer( return jsMultiArtifactCache.commitCompiledJsCode(this, compiledModule) } - val (cachedMainModule, cachedOtherModules) = jsMultiArtifactCache.getMainModuleAndDependencies(cachedProgram) + val cachedMainModule = cachedProgram.last() + val cachedOtherModules = cachedProgram.dropLast(1) val mainModuleCompilationOutput = cachedMainModule .compileModule(mainModuleName, true) .apply { - dependencies = cachedOtherModules.map { + dependencies += cachedOtherModules.map { it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiArtifactCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiArtifactCache.kt index f6a5d883769..9f6b3e7dc6c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiArtifactCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiArtifactCache.kt @@ -14,10 +14,8 @@ abstract class JsMultiArtifactCache { abstract fun loadProgramHeadersFromCache(): List abstract fun loadRequiredJsIrModules(crossModuleReferences: Map) abstract fun fetchCompiledJsCode(cacheInfo: T): CompilationOutputsCached? - abstract fun commitCompiledJsCode(cacheInfo: T, compilationOutputs: CompilationOutputsBuilt): CompilationOutputs - abstract fun fetchCompiledJsCodeForNullCacheInfo(): CompilationOutputs abstract fun loadJsIrModule(cacheInfo: T): JsIrModule - abstract fun getMainModuleAndDependencies(cacheInfo: List): Pair> + abstract fun commitCompiledJsCode(cacheInfo: T, compilationOutputs: CompilationOutputsBuilt): CompilationOutputs protected fun File.writeIfNotNull(data: String?) { if (data != null) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerFileCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerFileCache.kt index 1361ce9b361..0f609dcfa59 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerFileCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerFileCache.kt @@ -30,6 +30,7 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult private fun SrcFileArtifact.loadJsIrModuleHeaders(moduleArtifact: ModuleArtifact) = with(loadJsIrFragments()!!) { LoadedJsIrModuleHeaders( + mainFragment.mainFunction, mainFragment.run { asIrModuleHeader( getMainFragmentExternalName(moduleArtifact), @@ -95,6 +96,7 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult open class MainFileCachedInfo(moduleArtifact: ModuleArtifact, fileArtifact: SrcFileArtifact, moduleHeader: JsIrModuleHeader? = null) : SerializableCachedFileInfo(moduleArtifact, fileArtifact, moduleHeader) { + var mainFunctionTag: String? = null var exportFileCachedInfo: ExportFileCachedInfo? = null val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) } @@ -114,13 +116,33 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult 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) } + isModified -> cachedFileInfos.asSequence().map { it.fileArtifact.loadJsIrModuleHeaders(moduleArtifact) } + else -> cachedFileInfos.asSequence().map { + LoadedJsIrModuleHeaders( + it.mainFunctionTag, + it.jsIrHeader, + it.exportFileCachedInfo?.jsIrHeader + ) + } + } + + val mainHeaders = mutableListOf() + val exportHeaders = mutableListOf() + + for (loadedIrModuleHeaders in mainAndExportHeaders) { + mainHeaders.add(loadedIrModuleHeaders.mainHeader) + + loadedIrModuleHeaders.exportHeader + ?.let { exportHeaders.add(it) } + + loadedIrModuleHeaders.mainFunctionTag + .takeIf { mainFunctionTag == null } + ?.let { mainFunctionTag = it } } - val (mainHeaders, exportHeaders) = mainAndExportHeaders.map(LoadedJsIrModuleHeaders::toPair).unzip() jsIrHeader = mainHeaders.merge() - exportFileCachedInfo = exportHeaders.filterNotNull().takeIf { it.isNotEmpty() } + exportFileCachedInfo = exportHeaders + .takeIf { it.isNotEmpty() } ?.let { ExportFileCachedInfo.Merged( filePrefix, @@ -152,6 +174,8 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult class ModuleProxyFileCachedInfo(moduleArtifact: ModuleArtifact, moduleHeader: JsIrModuleHeader? = null) : CachedFileInfo(moduleArtifact, moduleHeader) { + var mainFunctionTag: String? = null + val jsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_JS) } val dtsFileArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(CACHED_FILE_D_TS) } val moduleHeaderArtifact by lazy(LazyThreadSafetyMode.NONE) { getArtifactWithName(JS_MODULE_HEADER) } @@ -162,6 +186,7 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult return generateProxyIrModuleWith( jsIrHeader.externalModuleName, jsIrHeader.externalModuleName, + mainFunctionTag, jsIrHeader.importedWithEffectInModuleWithName ) } @@ -206,6 +231,7 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult return mainFileCachedFileInfo.readModuleHeaderCache { mainFileCachedFileInfo.apply { exportFileCachedInfo = fetchFileInfoForExportedPart(this) + mainFunctionTag = ifTrue { readString() } loadSingleCachedFileInfo(this) } } @@ -213,7 +239,10 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult private fun ModuleArtifact.fetchModuleProxyFileInfo(): CachedFileInfo.ModuleProxyFileCachedInfo? { val mainFileCachedFileInfo = CachedFileInfo.ModuleProxyFileCachedInfo(this) - return mainFileCachedFileInfo.moduleHeaderArtifact?.useCodedInputIfExists { loadSingleCachedFileInfo(mainFileCachedFileInfo) } + return mainFileCachedFileInfo.moduleHeaderArtifact?.useCodedInputIfExists { + mainFileCachedFileInfo.mainFunctionTag = ifTrue { readString() } + loadSingleCachedFileInfo(mainFileCachedFileInfo) + } } private fun CodedInputStream.fetchFileInfoForExportedPart(mainCachedFileInfo: CachedFileInfo.MainFileCachedInfo): CachedFileInfo.ExportFileCachedInfo? { @@ -238,28 +267,38 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult is CachedFileInfo.MainFileCachedInfo -> { moduleHeaderArtifact?.useCodedOutput { ifNotNull(exportFileCachedInfo) { commitSingleFileInfo(it) } + ifNotNull(mainFunctionTag) { writeStringNoTag(it) } commitSingleFileInfo(this@commitFileInfo) } } is CachedFileInfo.ModuleProxyFileCachedInfo -> { moduleHeaderArtifact?.useCodedOutput { + ifNotNull(mainFunctionTag) { writeStringNoTag(it) } commitSingleFileInfo(this@commitFileInfo) } } is CachedFileInfo.ExportFileCachedInfo -> {} } - private fun ModuleArtifact.generateModuleProxyFileCachedInfo(importedWithEffectInModuleWithName: String? = null): CachedFileInfo { - return CachedFileInfo.ModuleProxyFileCachedInfo( - this, - generateProxyIrModuleWith(moduleExternalName, moduleExternalName, importedWithEffectInModuleWithName).makeModuleHeader() - ) + private fun ModuleArtifact.generateModuleProxyFileCachedInfo( + mainFunctionTag: String?, + importedWithEffectInModuleWithName: String? = null + ): CachedFileInfo { + val moduleHeader = generateProxyIrModuleWith( + moduleExternalName, + moduleExternalName, + mainFunctionTag, + importedWithEffectInModuleWithName + ).makeModuleHeader() + return CachedFileInfo.ModuleProxyFileCachedInfo(this, moduleHeader) + .also { it.mainFunctionTag = mainFunctionTag } } private fun ModuleArtifact.loadFileInfoFor(fileArtifact: SrcFileArtifact): CachedFileInfo.MainFileCachedInfo { val headers = fileArtifact.loadJsIrModuleHeaders(this) val mainCachedFileInfo = CachedFileInfo.MainFileCachedInfo(this, fileArtifact, headers.mainHeader) + .apply { mainFunctionTag = headers.mainFunctionTag } if (headers.exportHeader != null) { val tsDeclarationsHash = fileArtifact.loadJsIrFragments()?.exportFragment?.dts?.raw?.cityHash64() @@ -286,10 +325,6 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult is CachedFileInfo.ModuleProxyFileCachedInfo -> jsFileArtifact?.let { CachedFileArtifacts(it, null, dtsFileArtifact) } } - override fun getMainModuleAndDependencies(cacheInfo: List) = null to cacheInfo - - override fun fetchCompiledJsCodeForNullCacheInfo() = PerFileEntryPointCompilationOutput() - override fun fetchCompiledJsCode(cacheInfo: CachedFileInfo) = cacheInfo.cachedFiles?.let { (jsCodeFile, sourceMapFile, tsDeclarationsFile) -> jsCodeFile.ifExists { this } @@ -302,8 +337,7 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult compilationOutputs.writeJsCodeIntoModuleCache(jsCodeFile, jsMapFile) } ?: compilationOutputs - override fun loadJsIrModule(cacheInfo: CachedFileInfo): JsIrModule = - cacheInfo.loadJsIrModule() + override fun loadJsIrModule(cacheInfo: CachedFileInfo): JsIrModule = cacheInfo.loadJsIrModule() override fun loadProgramHeadersFromCache(): List { val mainModuleArtifact = moduleArtifacts.last() @@ -317,6 +351,13 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult override val CachedFileInfo.artifactName get() = jsIrHeader.externalModuleName override val CachedFileInfo.hasEffect get() = jsIrHeader.importedWithEffectInModuleWithName != null override val CachedFileInfo.hasExport get() = this is CachedFileInfo.MainFileCachedInfo && exportFileCachedInfo != null + override val CachedFileInfo.packageFqn get() = moduleFragmentToExternalName.excludeFileNameFromExternalName(jsIrHeader.moduleName) + override val CachedFileInfo.mainFunction + get() = when (this) { + is CachedFileInfo.MainFileCachedInfo -> mainFunctionTag + is CachedFileInfo.ModuleProxyFileCachedInfo -> mainFunctionTag + else -> error("Unexpected CachedFileInfo type ${this::class.simpleName}") + } override fun SrcFileArtifact.generateArtifact(module: ModuleArtifact) = when { isModified() -> module.loadFileInfoFor(this) @@ -329,10 +370,10 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult else -> CachedFileInfo.MainFileCachedInfo.Merged(map { it as CachedFileInfo.MainFileCachedInfo }) } - override fun ModuleArtifact.generateArtifact(moduleNameForEffects: String?) = + override fun ModuleArtifact.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?) = fetchModuleProxyFileInfo()?.takeIf { - it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects - } ?: generateModuleProxyFileCachedInfo(moduleNameForEffects) + it.mainFunction == mainFunctionTag && it.jsIrHeader.importedWithEffectInModuleWithName == moduleNameForEffects + } ?: generateModuleProxyFileCachedInfo(mainFunctionTag, moduleNameForEffects) } return perFileGenerator.generatePerFileArtifacts(moduleArtifacts) @@ -358,8 +399,9 @@ class JsPerFileCache(private val moduleArtifacts: List) : JsMult } private data class CachedFileArtifacts(val jsCodeFile: File, val sourceMapFile: File?, val tsDeclarationsFile: File?) - private data class LoadedJsIrModuleHeaders(val mainHeader: JsIrModuleHeader, val exportHeader: JsIrModuleHeader?) { - fun toPair() = mainHeader to exportHeader - } - + private data class LoadedJsIrModuleHeaders( + val mainFunctionTag: String?, + val mainHeader: JsIrModuleHeader, + val exportHeader: JsIrModuleHeader? + ) } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerModuleCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerModuleCache.kt index ab7484f87ea..83999e9938f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerModuleCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsPerModuleCache.kt @@ -57,12 +57,6 @@ class JsPerModuleCache(private val moduleArtifacts: List) : JsMu override fun loadJsIrModule(cacheInfo: CachedModuleInfo) = cacheInfo.artifact.loadJsIrModule() - override fun getMainModuleAndDependencies(cacheInfo: List) = - cacheInfo.last() to cacheInfo.dropLast(1) - - override fun fetchCompiledJsCodeForNullCacheInfo() = - error("Should never happen for per module granularity") - override fun fetchCompiledJsCode(cacheInfo: CachedModuleInfo) = cacheInfo.artifact.artifactsDir?.let { cacheDir -> val jsCodeFile = File(cacheDir, CACHED_MODULE_JS).ifExists { this } val sourceMapFile = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { this } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt new file mode 100644 index 00000000000..d0c1504ac45 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt @@ -0,0 +1,86 @@ +/* + * 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.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector +import org.jetbrains.kotlin.ir.backend.js.utils.isLoweredSuspendFunction +import org.jetbrains.kotlin.ir.backend.js.utils.isStringArrayParameter +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.util.toIrConst +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.runIf + +class MainFunctionCallWrapperLowering(private val context: JsIrBackendContext) : FileLoweringPass { + private val mainFunctionDetector = JsMainFunctionDetector(context) + private var IrSimpleFunction.mainFunctionWrapper by context.mapping.mainFunctionToItsWrapper + private val mainFunctionArgs by lazy(LazyThreadSafetyMode.NONE) { + context.mainCallArguments ?: error("Expect to have main call args at this point") + } + + override fun lower(irFile: IrFile) { + if (context.mainCallArguments == null) return + val mainFunction = mainFunctionDetector.getMainFunctionOrNull(irFile) ?: return + val mainFunctionWrapper = context.irFactory.stageController.restrictTo(mainFunction) { + mainFunction.generateWrapperForMainFunction().also { + mainFunction.mainFunctionWrapper = it + } + } + + irFile.declarations.add(mainFunctionWrapper) + } + + private fun IrSimpleFunction.generateWrapperForMainFunction(): IrSimpleFunction { + val originalFunctionSymbol = symbol + return context.irFactory.createSimpleFunction( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = JsIrBuilder.SYNTHESIZED_DECLARATION, + name = Name.identifier("mainWrapper"), + visibility = visibility, + isInline = false, + isExpect = false, + returnType = returnType, + modality = modality, + symbol = IrSimpleFunctionSymbolImpl(), + isTailrec = false, + isSuspend = false, + isOperator = false, + isInfix = false + ).also { + it.parent = parent + it.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply { + statements.add(JsIrBuilder.buildCall(originalFunctionSymbol).apply { + generateMainArguments().forEachIndexed(this::putValueArgument) + }) + } + } + } + + private fun IrSimpleFunction.generateMainArguments(): List { + val generateArgv = valueParameters.firstOrNull()?.isStringArrayParameter() ?: false + val generateContinuation = isLoweredSuspendFunction(context) + + return listOfNotNull( + runIf(generateArgv) { + JsIrBuilder.buildArray( + mainFunctionArgs.map { it.toIrConst(context.irBuiltIns.stringType) }, + valueParameters.first().type, + context.irBuiltIns.stringType + ) + }, + runIf(generateContinuation) { + JsIrBuilder.buildCall(context.coroutineEmptyContinuation.owner.getter!!.symbol) + } + ) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt index a97f36b7a4b..9a38961d063 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt @@ -20,6 +20,12 @@ val ModuleKind.extension: String else -> REGULAR_EXTENSION } +enum class TsCompilationStrategy { + NONE, + MERGED, + EACH_FILE +} + abstract class CompilationOutputs { var dependencies: Collection> = emptyList() @@ -31,7 +37,7 @@ abstract class CompilationOutputs { fun createWrittenFilesContainer(): MutableSet = LinkedHashSet(2 * (dependencies.size + 1) + 1) - open fun writeAll(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind): Collection { + open fun writeAll(outputDir: File, outputName: String, dtsStrategy: TsCompilationStrategy, moduleName: String, moduleKind: ModuleKind): Collection { val writtenFiles = createWrittenFilesContainer() fun File.writeAsJsFile(out: CompilationOutputs) { @@ -43,6 +49,12 @@ abstract class CompilationOutputs { writtenFiles += jsFile writtenFiles += jsMapFile + + out.tsDefinitions.takeIf { dtsStrategy == TsCompilationStrategy.EACH_FILE }?.let { + val tsFile = jsFile.dtsForJsFile + tsFile.writeText(listOf(it).toTypeScript(name, moduleKind)) + writtenFiles += tsFile + } } dependencies.forEach { (name, content) -> @@ -52,7 +64,7 @@ abstract class CompilationOutputs { val outputJsFile = outputDir.resolve("$outputName${moduleKind.extension}") outputJsFile.writeAsJsFile(this) - if (genDTS) { + if (dtsStrategy == TsCompilationStrategy.MERGED) { val dtsFile = outputJsFile.dtsForJsFile dtsFile.writeText(getFullTsDefinition(moduleName, moduleKind)) writtenFiles += dtsFile @@ -112,40 +124,6 @@ class CompilationOutputsBuilt( } } -// The output emulates the main module that has all the dependencies. In per-module we expect that the last processed module is a main module -// and after the compilation we rename it with the provided [outputName] and save all of its dependencies, but with the per-file mode we don't have -// this last "main" module, as a result we need to emulate it with the output. Also, it helps to save .d.ts files file-by-file instead of the generating -// one big main .d.ts file -class PerFileEntryPointCompilationOutput : CompilationOutputs() { - override val tsDefinitions: TypeScriptFragment? = null - override val jsProgram: JsProgram? = null - - override fun writeJsCode(outputJsFile: File, outputJsMapFile: File) {} - - override fun writeAll(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind): Collection { - val writtenFiles = createWrittenFilesContainer() - - dependencies.forEach { (name, content) -> - val dependencyFile = outputDir.resolve("$name${moduleKind.extension}").also { it.parentFile.mkdirs() } - val jsMapFile = dependencyFile.mapForJsFile - val jsFile = dependencyFile.normalizedAbsoluteFile - val tsFile = jsFile.dtsForJsFile - - content.writeJsCode(jsFile, jsMapFile) - - writtenFiles += jsFile - writtenFiles += jsMapFile - - content.tsDefinitions.takeIf { genDTS }?.let { - tsFile.writeText(listOf(it).toTypeScript(name, moduleKind)) - writtenFiles += tsFile - } - } - - return writtenFiles.also { deleteNonWrittenFiles(outputDir, it) } - } -} - class CompilationOutputsCached( private val jsCodeFile: File, private val sourceMapFile: File?, 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 6552cf70869..5ec62ccd3f3 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 @@ -48,12 +48,25 @@ val String.safeModuleName: String val IrModuleFragment.safeName: String get() = name.asString().safeModuleName -fun generateProxyIrModuleWith(safeName: String, externalName: String, importedWithEffectInModuleWithName: String? = null) = JsIrModule( - safeName, - externalName, - listOf(JsIrProgramFragment(safeName, "")), - importedWithEffectInModuleWithName = importedWithEffectInModuleWithName -) +fun generateProxyIrModuleWith( + safeName: String, + externalName: String, + mainFunction: String?, + importedWithEffectInModuleWithName: String? = null +): JsIrModule { + val programFragment = JsIrProgramFragment(safeName, "").apply { + mainFunction?.let { + this.mainFunction = it + this.nameBindings[it] = JsName("main", true) + } + } + return JsIrModule( + safeName, + externalName, + listOf(programFragment), + importedWithEffectInModuleWithName = importedWithEffectInModuleWithName + ) +} enum class JsGenerationGranularity { WHOLE_PROGRAM, @@ -127,8 +140,8 @@ class JsCodeGenerator( class IrModuleToJsTransformer( private val backendContext: JsIrBackendContext, - private val mainArguments: List?, moduleToName: Map = emptyMap(), + private val shouldReferMainFunction: Boolean = false, private val removeUnusedAssociatedObjects: Boolean = true, ) { private val shouldGeneratePolyfills = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_POLYFILLS) @@ -274,12 +287,14 @@ class IrModuleToJsTransformer( override val JsIrModules.artifactName get() = this.mainModule.externalModuleName override val JsIrModules.hasEffect get() = this.mainModule.importedWithEffectInModuleWithName != null override val JsIrModules.hasExport get() = this.exportModule != null + override val JsIrModules.packageFqn get() = this.mainModule.fragments.first().packageFqn + override val JsIrModules.mainFunction get() = this.mainModule.fragments.first().mainFunction override fun List.merge() = JsIrModules(map { it.mainModule }.merge(), mapNotNull { it.exportModule }.ifNotEmpty { merge() }) - override fun IrAndExportedDeclarations.generateArtifact(moduleNameForEffects: String?) = - JsIrModules(toJsIrProxyModule(moduleNameForEffects)) + override fun IrAndExportedDeclarations.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?) = + JsIrModules(toJsIrProxyModule(mainFunctionTag, moduleNameForEffects)) override fun IrFileExports.generateArtifact(module: IrAndExportedDeclarations) = takeIf { !file.couldBeSkipped() } ?.let { generateProgramFragment(it, mode) } @@ -316,10 +331,14 @@ class IrModuleToJsTransformer( ) } - private fun IrAndExportedDeclarations.toJsIrProxyModule(importedWithEffectInModuleWithName: String? = null): JsIrModule { + private fun IrAndExportedDeclarations.toJsIrProxyModule( + mainFunction: String?, + importedWithEffectInModuleWithName: String? = null + ): JsIrModule { return generateProxyIrModuleWith( fragment.safeName, moduleFragmentToNameMapper.getExternalNameFor(fragment), + mainFunction, importedWithEffectInModuleWithName ) } @@ -404,15 +423,6 @@ class IrModuleToJsTransformer( result.initializers.statements += staticContext.initializerBlock.statements result.eagerInitializers.statements += staticContext.eagerInitializerBlock.statements - if (mainArguments != null) { - JsMainFunctionDetector(backendContext).getMainFunctionOrNull(fileExports.file)?.let { - val jsName = staticContext.getNameForStaticFunction(it) - val generateArgv = it.valueParameters.firstOrNull()?.isStringArrayParameter() ?: false - val generateContinuation = it.isLoweredSuspendFunction(backendContext) - result.mainFunction = JsInvocation(jsName.makeRef(), generateMainArguments(generateArgv, generateContinuation, staticContext)).makeStmt() - } - } - backendContext.testFunsPerFile[fileExports.file]?.let { result.testFunInvocation = JsInvocation(staticContext.getNameForStaticFunction(it).makeRef()).makeStmt() result.suiteFn = staticContext.getNameForStaticFunction(backendContext.suiteFun!!.owner) @@ -422,6 +432,12 @@ class IrModuleToJsTransformer( val definitionSet = fileExports.file.declarations.toSet() + if (shouldReferMainFunction) { + JsMainFunctionDetector(backendContext).getMainFunctionOrNull(fileExports.file) + ?.let { backendContext.mapping.mainFunctionToItsWrapper[it] } + ?.let { result.mainFunction = definitionSet.computeTag(it) } + } + result.computeAndSaveNameBindings(definitionSet, nameGenerator) result.computeAndSaveImports(definitionSet, nameGenerator) result.computeAndSaveDefinitions(definitionSet, fileExports) @@ -494,25 +510,6 @@ class IrModuleToJsTransformer( } } - private fun generateMainArguments( - generateArgv: Boolean, - generateContinuation: Boolean, - staticContext: JsStaticContext, - ): List { - val mainArguments = this.mainArguments!! - val mainArgumentsArray = - if (generateArgv) JsArrayLiteral(mainArguments.map { JsStringLiteral(it) }) else null - - val continuation = if (generateContinuation) { - backendContext.coroutineEmptyContinuation.owner - .let { it.getter!! } - .let { staticContext.getNameForStaticFunction(it) } - .let { JsInvocation(it.makeRef()) } - } else null - - return listOfNotNull(mainArgumentsArray, continuation) - } - private fun IrFile.couldBeSkipped(): Boolean = declarations.all { it.origin == JsCodeOutliningLowering.OUTLINED_JS_CODE_ORIGIN } } 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 3681cfe6c8c..e59eb02f1c5 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 @@ -25,7 +25,7 @@ class JsIrProgramFragment(val name: String, val packageFqn: String) { val classes = mutableMapOf() val initializers = JsCompositeBlock() val eagerInitializers = JsCompositeBlock() - var mainFunction: JsStatement? = null + var mainFunction: String? = null var testFunInvocation: JsStatement? = null var suiteFn: JsName? = null val definitions = mutableSetOf() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/Merger.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/Merger.kt index b86cafa5546..14ba1258192 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/Merger.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/Merger.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs +import org.jetbrains.kotlin.idea.MainFunctionDetector +import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.serialization.js.ModuleKind @@ -59,7 +61,6 @@ class Merger( rename(f.initializers) rename(f.eagerInitializers) - f.mainFunction?.let { rename(it) } f.testFunInvocation?.let { rename(it) } f.suiteFn?.let { f.suiteFn = rename(it) } } @@ -247,7 +248,9 @@ class Merger( moduleBody.endRegion() } - val callToMain = fragments.sortedBy { it.packageFqn }.firstNotNullOfOrNull { it.mainFunction } + val fragmentWithMainFunction = JsMainFunctionDetector.pickMainFunctionFromCandidates(fragments) { + JsMainFunctionDetector.MainFunctionCandidate(it.packageFqn, it.mainFunction) + } val exportStatements = declareAndCallJsExporter() + additionalExports + transitiveJsExport() @@ -267,8 +270,10 @@ class Merger( statements.addWithComment("block: imports", importStatements) statements += moduleBody statements.addWithComment("block: exports", exportStatements) - if (generateCallToMain) { - callToMain?.let { this.statements += it } + if (generateCallToMain && fragmentWithMainFunction != null) { + val mainFunctionTag = fragmentWithMainFunction.mainFunction ?: error("Expect to have main function signature at this point") + val mainFunctionName = fragmentWithMainFunction.nameBindings[mainFunctionTag] ?: error("Expect to have name binding for tag $mainFunctionTag") + statements += JsInvocation(mainFunctionName.makeRef()).makeStmt() } this.statements += JsReturn(internalModuleName.makeRef()) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/ModuleFragmentToExternalName.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/ModuleFragmentToExternalName.kt index acb822d3c25..23494782af9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/ModuleFragmentToExternalName.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/ModuleFragmentToExternalName.kt @@ -42,6 +42,10 @@ class ModuleFragmentToExternalName(private val jsOutputNamesMapping: Map { @@ -16,10 +18,12 @@ interface PerFileGenerator { val Artifact.artifactName: String val Artifact.hasEffect: Boolean val Artifact.hasExport: Boolean + val Artifact.packageFqn: String + val Artifact.mainFunction: String? fun List.merge(): Artifact fun File.generateArtifact(module: Module): Artifact? - fun Module.generateArtifact(moduleNameForEffects: String?): Artifact + fun Module.generateArtifact(mainFunctionTag: String?, moduleNameForEffects: String?): Artifact fun generatePerFileArtifacts(modules: List): List { var someModuleHasEffect = false @@ -29,8 +33,8 @@ interface PerFileGenerator { var hasModuleLevelEffect = false var hasFileWithExportedDeclaration = false - for (file in module.fileList) { - val generatedArtifact = file.generateArtifact(module) ?: continue + val artifacts = module.fileList.mapNotNull { + val generatedArtifact = it.generateArtifact(module) ?: return@mapNotNull null if (generatedArtifact.hasExport) { hasFileWithExportedDeclaration = true @@ -41,15 +45,28 @@ interface PerFileGenerator { } putToMultiMap(generatedArtifact.artifactName, generatedArtifact) + + generatedArtifact } if (hasModuleLevelEffect) { someModuleHasEffect = true } - if (hasFileWithExportedDeclaration || hasModuleLevelEffect || (module.isMain && someModuleHasEffect)) { + val mainFunctionTag = runIf(module.isMain) { + JsMainFunctionDetector + .pickMainFunctionFromCandidates(artifacts) { + JsMainFunctionDetector.MainFunctionCandidate( + it.packageFqn, + it.mainFunction + ) + } + ?.mainFunction + } + + if (mainFunctionTag != null || hasFileWithExportedDeclaration || hasModuleLevelEffect || (module.isMain && someModuleHasEffect)) { val proxyArtifact = - module.generateArtifact(mainModuleName.takeIf { !module.isMain && hasModuleLevelEffect }) ?: continue + module.generateArtifact(mainFunctionTag, mainModuleName.takeIf { !module.isMain && hasModuleLevelEffect }) ?: continue putToMultiMap(proxyArtifact.artifactName, proxyArtifact) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsMainFunctionDetector.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsMainFunctionDetector.kt index 7c4a6e33b47..a4623dd5ba2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsMainFunctionDetector.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsMainFunctionDetector.kt @@ -71,6 +71,17 @@ class JsMainFunctionDetector(val context: JsCommonBackendContext) { return resultPair?.second } + + class MainFunctionCandidate(val packageFqn: String, val mainFunctionTag: String?) + companion object { + inline fun pickMainFunctionFromCandidates(candidates: List, convertToCandidate: (T) -> MainFunctionCandidate): T? { + return candidates + .map { it to convertToCandidate(it) } + .sortedBy { it.second.packageFqn } + .firstOrNull { it.second.mainFunctionTag != null } + ?.first + } + } } 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 4384f966983..e2356a56c1a 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 @@ -104,7 +104,7 @@ private class JsIrAstDeserializer(private val source: ByteArray) { readRepeated { classes[nameTable[readInt()]] = readIrIcClassModel() } ifTrue { testFunInvocation = readStatement() } - ifTrue { mainFunction = readStatement() } + ifTrue { mainFunction = readString() } ifTrue { dts = TypeScriptFragment(readString()) } ifTrue { suiteFn = nameTable[readInt()] } 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 1fd49906bb9..8adf0a21869 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 @@ -156,7 +156,7 @@ private class JsIrAstSerializer { } ifNotNull(fragment.mainFunction) { - writeStatement(it) + writeString(it) } ifNotNull(fragment.dts) { diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/TestModel.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/TestModel.kt index b50ec82ae9b..96e05271efd 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/TestModel.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/TestModel.kt @@ -17,7 +17,8 @@ class ProjectInfo( val steps: List, val muted: Boolean, val moduleKind: ModuleKind, - val ignoredGranularities: Set + val ignoredGranularities: Set, + val callMain: Boolean ) { class ProjectBuildStep( @@ -71,6 +72,7 @@ class ModuleInfo(val moduleName: String) { } const val PROJECT_INFO_FILE = "project.info" +private const val CALL_MAIN = "CALL_MAIN" private const val MODULES_LIST = "MODULES" private const val MODULES_KIND = "MODULE_KIND" private const val LIBS_LIST = "libs" @@ -173,6 +175,7 @@ class ProjectInfoParser(infoFile: File) : InfoParser(infoFile) { val steps = mutableListOf() val ignoredGranularities = mutableSetOf() var muted = false + var callMain = false var moduleKind = ModuleKind.ES loop { line -> @@ -191,6 +194,7 @@ class ProjectInfoParser(infoFile: File) : InfoParser(infoFile) { when { op == MODULES_LIST -> libraries += split[1].splitAndTrim() + op == CALL_MAIN && split[1].trim() == "true" -> callMain = true op == IGNORE_PER_FILE && split[1].trim() == "true" -> ignoredGranularities += JsGenerationGranularity.PER_FILE op == IGNORE_PER_MODULE && split[1].trim() == "true" -> ignoredGranularities += JsGenerationGranularity.PER_MODULE op == MODULES_KIND -> moduleKind = split[1].trim() @@ -222,7 +226,7 @@ class ProjectInfoParser(infoFile: File) : InfoParser(infoFile) { false } - return ProjectInfo(entryName, libraries, steps, muted, moduleKind, ignoredGranularities) + return ProjectInfo(entryName, libraries, steps, muted, moduleKind, ignoredGranularities, callMain) } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt b/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt index db8bf0c73f4..7df441ee4f4 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt @@ -605,14 +605,15 @@ class GenerateIrRuntime { symbolTable, additionalExportedDeclarationNames = emptySet(), keep = emptySet(), - configuration + configuration, + null ) ExternalDependenciesGenerator(symbolTable, listOf(jsLinker)).generateUnboundSymbolsAsDependencies() jsPhases.invokeToplevel(phaseConfig, context, listOf(module)) - val transformer = IrModuleToJsTransformer(context, null) + val transformer = IrModuleToJsTransformer(context, shouldReferMainFunction = false) return transformer.generateModule(listOf(module), setOf(TranslationMode.PER_MODULE_DEV), false) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt index 36a06bde040..ad1b92962f9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -25,10 +25,7 @@ import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo import org.jetbrains.kotlin.ir.backend.js.WholeWorldStageController import org.jetbrains.kotlin.ir.backend.js.ic.* import org.jetbrains.kotlin.ir.backend.js.jsPhases -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.extension -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.* import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.test.converters.ClassicJsBackendFacade @@ -44,6 +41,7 @@ import org.jetbrains.kotlin.test.builders.LanguageVersionSettingsBuilder import org.jetbrains.kotlin.test.util.JUnit4Assertions import org.jetbrains.kotlin.test.utils.TestDisposable import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty +import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.junit.ComparisonFailure import org.junit.jupiter.api.AfterEach import java.io.File @@ -313,11 +311,16 @@ abstract class AbstractInvalidationTest( ) } - private fun writeJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs): List { + private fun writeJsCode( + stepId: Int, + mainModuleName: String, + jsOutput: CompilationOutputs, + dtsStrategy: TsCompilationStrategy + ): List { val compiledJsFiles = jsOutput.writeAll( jsDir, mainModuleName, - true, + dtsStrategy, mainModuleName, projectInfo.moduleKind ).filter { @@ -341,6 +344,12 @@ abstract class AbstractInvalidationTest( fun execute() { if (granularity in projectInfo.ignoredGranularities) return + val mainArguments = runIf(projectInfo.callMain) { emptyList() } + val dtsStrategy = when (granularity) { + JsGenerationGranularity.PER_FILE -> TsCompilationStrategy.EACH_FILE + else -> TsCompilationStrategy.MERGED + } + for (projStep in projectInfo.steps) { val testInfo = projStep.order.map { setupTestStep(projStep, it) } @@ -363,10 +372,10 @@ abstract class AbstractInvalidationTest( cacheDir = buildDir.resolve("incremental-cache").absolutePath, compilerConfiguration = configuration, irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) }, - mainArguments = null, compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC( mainModule, + mainArguments, cfg, granularity, getPhaseConfig(projStep.id), @@ -390,7 +399,7 @@ abstract class AbstractInvalidationTest( ) val (jsOutput, rebuiltModules) = jsExecutableProducer.buildExecutable(granularity, outJsProgram = true) - val writtenFiles = writeJsCode(projStep.id, mainModuleName, jsOutput) + val writtenFiles = writeJsCode(projStep.id, mainModuleName, jsOutput, dtsStrategy) verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, dirtyData) verifyJsCode(projStep.id, mainModuleName, writtenFiles) 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 aa06c1d4400..c1c4671bf48 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 @@ -138,10 +138,13 @@ class JsIrBackendFacade( PhaseConfig(jsPhases) } + val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module) + .run { if (shouldBeGenerated()) arguments() else null } val loweredIr = compileIr( irModuleFragment.apply { resolveTestPaths() }, MainModule.Klib(inputArtifact.outputFile.absolutePath), + mainArguments, configuration, dependencyModules.onEach { it.resolveTestPaths() }, emptyMap(), @@ -157,12 +160,10 @@ class JsIrBackendFacade( granularity = granularity, ) - return loweredIr2JsArtifact(module, loweredIr) + return loweredIr2JsArtifact(module, loweredIr, mainArguments != null) } - private fun loweredIr2JsArtifact(module: TestModule, loweredIr: LoweredIr): BinaryArtifacts.Js { - val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module) - .run { if (shouldBeGenerated()) arguments() else null } + private fun loweredIr2JsArtifact(module: TestModule, loweredIr: LoweredIr, shouldReferMainFunction: Boolean): BinaryArtifacts.Js { val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in module.directives val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives @@ -178,12 +179,12 @@ class JsIrBackendFacade( val transformer = IrModuleToJsTransformer( loweredIr.context, - mainArguments, moduleToName = runIf(isEsModules) { loweredIr.allModules.associateWith { "./${getJsArtifactSimpleName(testServices, it.safeName)}_v5".minifyIfNeed() } - } ?: emptyMap() + } ?: emptyMap(), + shouldReferMainFunction, ) // If runIrDce then include DCE results // If perModuleOnly then skip whole program @@ -290,7 +291,7 @@ class JsIrBackendFacade( val tmpBuildDir = rootDir.resolve("tmp-build") // CompilationOutputs keeps the `outputDir` clean by removing all outdated JS and other unknown files. // To ensure that useful files around `outputFile`, such as irdump, are not removed, use `tmpBuildDir` instead. - val allJsFiles = writeAll(tmpBuildDir, outputFile.nameWithoutExtension, false, moduleId, moduleKind).filter { + val allJsFiles = writeAll(tmpBuildDir, outputFile.nameWithoutExtension, TsCompilationStrategy.NONE, moduleId, moduleKind).filter { it.extension == "js" || it.extension == "mjs" } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java index ed55d6f98f6..33023fc1745 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java @@ -343,6 +343,12 @@ public class JsFirInvalidationPerFileTestGenerated extends AbstractJsFirInvalida runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java index af47fe4d078..69123b7fc36 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java @@ -343,6 +343,12 @@ public class JsFirInvalidationPerModuleTestGenerated extends AbstractJsFirInvali runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java index 9de5210334a..b9c62749ee5 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java @@ -343,6 +343,12 @@ public class JsIrES6InvalidationPerFileTestGenerated extends AbstractJsIrES6Inva runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java index ebda76f7c7c..983139d5375 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java @@ -343,6 +343,12 @@ public class JsIrES6InvalidationPerModuleTestGenerated extends AbstractJsIrES6In runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java index 4606fccfee4..8abcee275ea 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java @@ -343,6 +343,12 @@ public class JsIrInvalidationPerFileTestGenerated extends AbstractJsIrInvalidati runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java index 93ccc31e899..906eada32f3 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java @@ -343,6 +343,12 @@ public class JsIrInvalidationPerModuleTestGenerated extends AbstractJsIrInvalida runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/"); } + @Test + @TestMetadata("mainFunction") + public void testMainFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/mainFunction/"); + } + @Test @TestMetadata("mainModuleInvalidation") public void testMainModuleInvalidation() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java index 48ecea61e85..8d247819ab3 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java @@ -2598,6 +2598,64 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest { } } + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/box/esModules/native") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java index ed0071d167b..a83817ca06f 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.java @@ -2704,6 +2704,64 @@ public class FirJsES6BoxTestGenerated extends AbstractFirJsES6BoxTest { } } + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/box/esModules/native") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java index 2a957b1a7e8..701ffb21eb0 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java @@ -2704,6 +2704,64 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { } } + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/box/esModules/native") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 3745ca4d8bb..79cd187de06 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -2598,6 +2598,64 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { } } + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/box/esModules/native") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.translator/testData/box/esModules/main/differentMains.kt b/js/js.translator/testData/box/esModules/main/differentMains.kt new file mode 100644 index 00000000000..387d33dc5ba --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/differentMains.kt @@ -0,0 +1,24 @@ +// EXPECTED_REACHABLE_NODES: 1281 +// ES_MODULES +// CALL_MAIN + +var ok: String = "OK" + +fun main(args: Array) { + ok += "Fail Int" +} + +fun main(args: Array) { + ok += "Fail IN" +} + +fun main(args: Array): Unit? { + ok += "Fail return Unit?" + return Unit +} + +fun Any.main(args: Array) { + ok += "Fail Any.main(...)" +} + +fun box() = ok \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/incremental.kt b/js/js.translator/testData/box/esModules/main/incremental.kt new file mode 100644 index 00000000000..a297a9937a9 --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/incremental.kt @@ -0,0 +1,56 @@ +// EXPECTED_REACHABLE_NODES: 1281 +// ES_MODULES +// CALL_MAIN + +// FILE: ok.kt + +package ok + +var ok: String = "fail" + +// FILE: 1.kt +// RECOMPILE + +package a.a + +import ok.* + +fun main(args: Array) { + ok = "fail: b.b" +} + +// FILE: 0.kt + +package b + +import ok.* + +fun main(args: Array) { + ok = "fail: b" +} + +// FILE: 2.kt + +package a + +import ok.* + +fun main(args: Array) { + ok = "OK" +} + +// FILE: 3.kt + +package a.b + +import ok.* + +fun main(args: Array) { + ok = "fail: a.b" +} + +// FILE: main.kt + +import ok.* + +fun box() = ok \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/noArgs.kt b/js/js.translator/testData/box/esModules/main/noArgs.kt new file mode 100644 index 00000000000..adce93627c8 --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/noArgs.kt @@ -0,0 +1,11 @@ +// EXPECTED_REACHABLE_NODES: 1281 +// ES_MODULES +// CALL_MAIN + +var ok: String = "fail" + +fun main() { + ok = "OK" +} + +fun box() = ok \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/simple.kt b/js/js.translator/testData/box/esModules/main/simple.kt new file mode 100644 index 00000000000..434f0683c4d --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/simple.kt @@ -0,0 +1,13 @@ +// EXPECTED_REACHABLE_NODES: 1281 +// ES_MODULES +// CALL_MAIN + +var ok: String = "fail" + +fun main(args: Array) { + if (0 != args.size) error("fail") + + ok = "OK" +} + +fun box() = ok \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/suspendMain.kt b/js/js.translator/testData/box/esModules/main/suspendMain.kt new file mode 100644 index 00000000000..fcf0eeda5e1 --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/suspendMain.kt @@ -0,0 +1,27 @@ +// EXPECTED_REACHABLE_NODES: 1296 +// ES_MODULES +// CALL_MAIN + +import kotlin.coroutines.* + +var ok: String = "fail" + +var callback: () -> Unit = {} + +suspend fun main(args: Array) { + if (0 != args.size) error("Fail") + + suspendCoroutine { cont -> + callback = { + cont.resume(Unit) + } + } + + ok = "OK" +} + +fun box(): String { + if ("fail" != ok) return "Fail" + callback() + return ok +} \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt b/js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt new file mode 100644 index 00000000000..1f8bb664724 --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt @@ -0,0 +1,25 @@ +// EXPECTED_REACHABLE_NODES: 1296 +// ES_MODULES +// CALL_MAIN + +import kotlin.coroutines.* + +var ok: String = "fail" + +var callback: () -> Unit = {} + +suspend fun main() { + suspendCoroutine { cont -> + callback = { + cont.resume(Unit) + } + } + + ok = "OK" +} + +fun box(): String { + if ("fail" != ok) error("Fail") + callback() + return ok +} \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/suspendMainThrows.kt b/js/js.translator/testData/box/esModules/main/suspendMainThrows.kt new file mode 100644 index 00000000000..b7404b06a03 --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/suspendMainThrows.kt @@ -0,0 +1,30 @@ +// EXPECTED_REACHABLE_NODES: 1299 +// ES_MODULES +// CALL_MAIN + +import kotlin.coroutines.* + +var callback: () -> Unit = {} + +val exception = Exception() + +suspend fun main() { + + suspendCoroutine { cont -> + callback = { + cont.resume(Unit) + } + } + + throw exception +} + +fun box(): String { + try { + callback() + } catch (e: Exception) { + if (e !== exception) return "Fail" + } + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/main/twoMains.kt b/js/js.translator/testData/box/esModules/main/twoMains.kt new file mode 100644 index 00000000000..dc4665026cb --- /dev/null +++ b/js/js.translator/testData/box/esModules/main/twoMains.kt @@ -0,0 +1,18 @@ +// EXPECTED_REACHABLE_NODES: 1281 +// ES_MODULES +// CALL_MAIN + +var o: String = "fail O" +var k: String = "K" + +fun main() { + k = "fail K" +} + +fun main(args: Array) { + if (args.size != 0) error("Fail") + + o = "O" +} + +fun box() = o + k \ No newline at end of file diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.1.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.1.kt new file mode 100644 index 00000000000..07d192ec67a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.1.kt @@ -0,0 +1,7 @@ +package foo.bar + +var ok = "Fail" + +fun main() { + ok = "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.2.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.2.kt new file mode 100644 index 00000000000..cdd3bee1ceb --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.2.kt @@ -0,0 +1,20 @@ +package foo.bar + +var ok = "OK" + +fun main(args: Array) { + ok += "Fail Int" +} + +fun main(args: Array) { + ok += "Fail IN" +} + +fun main(args: Array): Unit? { + ok += "Fail return Unit?" + return Unit +} + +fun Any.main(args: Array) { + ok += "Fail Any.main(...)" +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.3.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.3.kt new file mode 100644 index 00000000000..64c6da4eb35 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.3.kt @@ -0,0 +1,19 @@ +package foo.bar + +import kotlin.coroutines.* + +var ok: String = "fail" + +var callback: () -> Unit = {} + +suspend fun main(args: Array) { + if (0 != args.size) error("Fail") + + suspendCoroutine { cont -> + callback = { + cont.resume(Unit) + } + } + + ok = "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.4.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.4.kt new file mode 100644 index 00000000000..e5fd0c35762 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/f.4.kt @@ -0,0 +1,11 @@ +package foo.bar + +var ok = "fail" + +fun main(args: Array) { + if (args.size != 0) { + ok = "Fail with args zie" + } else { + ok = "OK" + } +} \ No newline at end of file diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/l.5.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/l.5.kt new file mode 100644 index 00000000000..c5991bf4dc8 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/l.5.kt @@ -0,0 +1,7 @@ +package foo + +import foo.bar.ok + +fun main() { + ok = "OK2" +} \ No newline at end of file diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.0.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.0.kt new file mode 100644 index 00000000000..a56735d4742 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.0.kt @@ -0,0 +1,10 @@ +var ok = "Fail" +fun main() { + ok = "OK" +} +fun box(stepId: Int): String { + return when (stepId) { + 0 -> ok + else -> "Unknown" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.1.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.1.kt new file mode 100644 index 00000000000..f673e68bc02 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.1.kt @@ -0,0 +1,13 @@ +import foo.bar.ok + +fun box(stepId: Int): String { + return when (stepId) { + 0 -> ok + 1 -> ok + 2 -> ok + 3 -> ok + 4 -> ok + 5 -> if (ok != "OK2") "Fail" else "OK" + else -> "Unknown" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.3.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.3.kt new file mode 100644 index 00000000000..481884d2235 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.3.kt @@ -0,0 +1,18 @@ +import foo.bar.ok +import foo.bar.callback + +fun box(stepId: Int): String { + return when (stepId) { + 0 -> ok + 1 -> ok + 2 -> ok + 3 -> { + if (ok != "fail") return "Fail" + callback() + ok + } + 4 -> ok + 5 -> if (ok != "OK2") "Fail" else "OK" + else -> "Unknown" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.4.kt b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.4.kt new file mode 100644 index 00000000000..f673e68bc02 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/m.4.kt @@ -0,0 +1,13 @@ +import foo.bar.ok + +fun box(stepId: Int): String { + return when (stepId) { + 0 -> ok + 1 -> ok + 2 -> ok + 3 -> ok + 4 -> ok + 5 -> if (ok != "OK2") "Fail" else "OK" + else -> "Unknown" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/main/module.info b/js/js.translator/testData/incremental/invalidation/mainFunction/main/module.info new file mode 100644 index 00000000000..3c0524ed98e --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/main/module.info @@ -0,0 +1,29 @@ +STEP 0: + modifications: + U : m.0.kt -> m.kt + added file: m.kt +STEP 1: + modifications: + U : m.1.kt -> m.kt + U : f.1.kt -> f.kt + added file: f.kt + modified ir: m.kt +STEP 2: + modifications: + U : f.2.kt -> f.kt + modified ir: f.kt +STEP 3: + modifications: + U : f.3.kt -> f.kt + U : m.3.kt -> m.kt + modified ir: f.kt, m.kt +STEP 4: + modifications: + U : f.4.kt -> f.kt + U : m.4.kt -> m.kt + modified ir: f.kt, m.kt +STEP 5: + modifications: + U : l.5.kt -> l.kt + added file: l.kt + updated exports: f.kt diff --git a/js/js.translator/testData/incremental/invalidation/mainFunction/project.info b/js/js.translator/testData/incremental/invalidation/mainFunction/project.info new file mode 100644 index 00000000000..a7a63cff9e8 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/mainFunction/project.info @@ -0,0 +1,27 @@ +MODULES: main +CALL_MAIN: true + +STEP 0: + libs: main + dirty js modules: main + dirty js files: main/m, main/m.export, main +STEP 1: + libs: main + dirty js modules: main + dirty js files: main/foo/bar/f, main/m, main +STEP 2: + libs: main + dirty js modules: main + dirty js files: main/foo/bar/f, main +STEP 3: + libs: main + dirty js modules: main + dirty js files: main/foo/bar/f, main/m, main +STEP 4: + libs: main + dirty js modules: main + dirty js files: main/foo/bar/f, main/m, main +STEP 5: + libs: main + dirty js modules: main + dirty js files: main/foo/l, main/foo/bar/f, main diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java index cb45c5aed7d..10a4437ae2e 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmJsTranslatorTestGenerated.java @@ -356,6 +356,64 @@ public class FirWasmJsTranslatorTestGenerated extends AbstractFirWasmJsTranslato runTest("js/js.translator/testData/box/esModules/jsName/jsTopLevelClashes.kt"); } } + + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } } @Nested diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java index bd716dd2eb5..eba9a2966a3 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmJsTranslatorTestGenerated.java @@ -356,6 +356,64 @@ public class K1WasmJsTranslatorTestGenerated extends AbstractK1WasmJsTranslatorT runTest("js/js.translator/testData/box/esModules/jsName/jsTopLevelClashes.kt"); } } + + @Nested + @TestMetadata("js/js.translator/testData/box/esModules/main") + @TestDataPath("$PROJECT_ROOT") + public class Main { + @Test + public void testAllFilesPresentInMain() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/main"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + + @Test + @TestMetadata("differentMains.kt") + public void testDifferentMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/differentMains.kt"); + } + + @Test + @TestMetadata("incremental.kt") + public void testIncremental() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/incremental.kt"); + } + + @Test + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/noArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/simple.kt"); + } + + @Test + @TestMetadata("suspendMain.kt") + public void testSuspendMain() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMain.kt"); + } + + @Test + @TestMetadata("suspendMainNoArgs.kt") + public void testSuspendMainNoArgs() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainNoArgs.kt"); + } + + @Test + @TestMetadata("suspendMainThrows.kt") + public void testSuspendMainThrows() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/suspendMainThrows.kt"); + } + + @Test + @TestMetadata("twoMains.kt") + public void testTwoMains() throws Exception { + runTest("js/js.translator/testData/box/esModules/main/twoMains.kt"); + } + } } @Nested