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 1d7dc3fce27..07a0d57f5ec 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 @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.cli.js import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.text.StringUtil -import org.jetbrains.kotlin.KtSourceFile +import org.jetbrains.kotlin.analyzer.CompilationErrorException import org.jetbrains.kotlin.backend.common.CompilationException import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr @@ -482,7 +482,7 @@ class K2JsIrCompiler : CLICompiler() { friendLibraries: List, arguments: K2JSCompilerArguments, outputKlibPath: String - ): ModulesStructure? { + ): ModulesStructure { val configuration = environmentForJS.configuration val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter() @@ -492,7 +492,7 @@ class K2JsIrCompiler : CLICompiler() { val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: LookupTracker.DO_NOTHING - val outputs = if ( + val analyzedOutput = if ( configuration.getBoolean(CommonConfigurationKeys.USE_FIR) && configuration.getBoolean(CommonConfigurationKeys.USE_LIGHT_TREE) ) { val groupedSources = collectSources(configuration, environmentForJS.project, messageCollector) @@ -506,38 +506,46 @@ class K2JsIrCompiler : CLICompiler() { ktSourceFiles = groupedSources.commonSources + groupedSources.platformSources, libraries = libraries, friendLibraries = friendLibraries, - messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], lookupTracker = lookupTracker, - ) ?: return null + ) } else { compileModuleToAnalyzedFirWithPsi( moduleStructure = moduleStructure, ktFiles = environmentForJS.getSourceFiles(), libraries = libraries, friendLibraries = friendLibraries, - messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], lookupTracker = lookupTracker, - ) ?: return null + ) } // FIR2IR - val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter) + val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter) if (configuration.getBoolean(CommonConfigurationKeys.INCREMENTAL_COMPILATION)) { - if (shouldGoToNextIcRound(moduleStructure, outputs, fir2IrActualizedResult)) { + // TODO: During checking the next round, fir serializer may throw an exception, e.g. + // during annotation serialization when it cannot find the removed constant + // (see ConstantValueUtils.kt:convertToConstantValues()) + // This happens because we check the next round before compilation errors. + // Test reproducer: testFileWithConstantRemoved + // Issue: https://youtrack.jetbrains.com/issue/KT-58824/ + if (shouldGoToNextIcRound(moduleStructure, analyzedOutput.output, fir2IrActualizedResult)) { throw IncrementalNextRoundException() } } + if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) { + throw CompilationErrorException() + } + // Serialize klib if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) { serializeFirKlib( moduleStructure = moduleStructure, - firOutputs = outputs, + firOutputs = analyzedOutput.output, fir2IrActualizedResult = fir2IrActualizedResult, outputKlibPath = outputKlibPath, messageCollector = messageCollector, diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt index 217ee51c62f..c933a933c2b 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt @@ -55,27 +55,18 @@ inline fun compileModuleToAnalyzedFir( files: List, libraries: List, friendLibraries: List, - messageCollector: MessageCollector, - diagnosticsReporter: BaseDiagnosticsCollector, incrementalDataProvider: IncrementalDataProvider?, lookupTracker: LookupTracker?, - fileHasSyntaxErrors: (F) -> Boolean, noinline isCommonSource: (F) -> Boolean, noinline fileBelongsToModule: (F, String) -> Boolean, buildResolveAndCheckFir: (FirSession, List) -> ModuleCompilerAnalyzedOutput, -): List? { - val renderDiagnosticNames = moduleStructure.compilerConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME) - +): List { // FIR val extensionRegistrars = FirExtensionRegistrar.getInstances(moduleStructure.project) val mainModuleName = moduleStructure.compilerConfiguration.get(CommonConfigurationKeys.MODULE_NAME)!! val escapedMainModuleName = Name.special("<$mainModuleName>") - val syntaxErrors = files.fold(false) { errorsFound, file -> - fileHasSyntaxErrors(file) or errorsFound - } - val binaryModuleData = BinaryModuleData.initialize(escapedMainModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices) val dependencyList = DependencyListForCliModule.build(binaryModuleData) { dependencies(libraries.map { Paths.get(it).toAbsolutePath() }) @@ -97,40 +88,61 @@ inline fun compileModuleToAnalyzedFir( buildResolveAndCheckFir(it.session, it.files) } - if (syntaxErrors || diagnosticsReporter.hasErrors) { - FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(diagnosticsReporter, messageCollector, renderDiagnosticNames) - return null - } - return outputs } +open class AnalyzedFirOutput(val output: List) { + protected open fun checkSyntaxErrors(messageCollector: MessageCollector) = false + + fun reportCompilationErrors( + moduleStructure: ModulesStructure, + diagnosticsReporter: BaseDiagnosticsCollector, + messageCollector: MessageCollector, + ): Boolean { + if (checkSyntaxErrors(messageCollector) || diagnosticsReporter.hasErrors) { + val renderName = moduleStructure.compilerConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME) + FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(diagnosticsReporter, messageCollector, renderName) + return true + } + + return false + } +} + +class AnalyzedFirWithPsiOutput( + output: List, + private val compiledFiles: List +) : AnalyzedFirOutput(output) { + override fun checkSyntaxErrors(messageCollector: MessageCollector): Boolean { + return compiledFiles.fold(false) { errorsFound, file -> + AnalyzerWithCompilerReport.reportSyntaxErrors(file, messageCollector).isHasErrors or errorsFound + } + } +} + fun compileModuleToAnalyzedFirWithPsi( moduleStructure: ModulesStructure, ktFiles: List, libraries: List, friendLibraries: List, - messageCollector: MessageCollector, diagnosticsReporter: BaseDiagnosticsCollector, incrementalDataProvider: IncrementalDataProvider?, lookupTracker: LookupTracker?, -): List? { - return compileModuleToAnalyzedFir( +): AnalyzedFirWithPsiOutput { + val output = compileModuleToAnalyzedFir( moduleStructure, ktFiles, libraries, friendLibraries, - messageCollector, - diagnosticsReporter, incrementalDataProvider, lookupTracker, - fileHasSyntaxErrors = { AnalyzerWithCompilerReport.reportSyntaxErrors(it, messageCollector).isHasErrors }, isCommonSource = isCommonSourceForPsi, fileBelongsToModule = fileBelongsToModuleForPsi, buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFirFromKtFiles(session, files, diagnosticsReporter) }, ) + return AnalyzedFirWithPsiOutput(output, ktFiles) } fun compileModulesToAnalyzedFirWithLightTree( @@ -139,27 +151,24 @@ fun compileModulesToAnalyzedFirWithLightTree( ktSourceFiles: List, libraries: List, friendLibraries: List, - messageCollector: MessageCollector, diagnosticsReporter: BaseDiagnosticsCollector, incrementalDataProvider: IncrementalDataProvider?, lookupTracker: LookupTracker?, -): List? { - return compileModuleToAnalyzedFir( +): AnalyzedFirOutput { + val output = compileModuleToAnalyzedFir( moduleStructure, ktSourceFiles, libraries, friendLibraries, - messageCollector, - diagnosticsReporter, incrementalDataProvider, lookupTracker, - fileHasSyntaxErrors = { false }, isCommonSource = { groupedSources.isCommonSourceForLt(it) }, fileBelongsToModule = { file, it -> groupedSources.fileBelongsToModuleForLt(file, it) }, buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFirViaLightTree(session, files, diagnosticsReporter, null) }, ) + return AnalyzedFirOutput(output) } fun transformFirToIr( diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt index 223f8a116cf..eaf317f0546 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import org.jetbrains.kotlin.cli.js.klib.compileModuleToAnalyzedFirWithPsi import org.jetbrains.kotlin.cli.js.klib.serializeFirKlib import org.jetbrains.kotlin.cli.js.klib.transformFirToIr -import org.jetbrains.kotlin.codegen.ProjectInfo import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.ir.backend.js.MainModule @@ -64,34 +63,36 @@ abstract class FirAbstractInvalidationTest( friendDependenciesPaths = friendLibraries ) - val outputs = compileModuleToAnalyzedFirWithPsi( + val analyzedOutput = compileModuleToAnalyzedFirWithPsi( moduleStructure = moduleStructure, ktFiles = sourceFiles, libraries = libraries, friendLibraries = friendLibraries, - messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = null, lookupTracker = null, ) - if (outputs != null) { - val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter) + val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter) - serializeFirKlib( - moduleStructure = moduleStructure, - firOutputs = outputs, - fir2IrActualizedResult = fir2IrActualizedResult, - outputKlibPath = outputKlibFile.absolutePath, - messageCollector = messageCollector, - diagnosticsReporter = diagnosticsReporter, - jsOutputName = moduleName - ) - } - - if (messageCollector.hasErrors()) { + if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) { val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) throw AssertionError("The following errors occurred compiling test:\n$messages") } + + serializeFirKlib( + moduleStructure = moduleStructure, + firOutputs = analyzedOutput.output, + fir2IrActualizedResult = fir2IrActualizedResult, + outputKlibPath = outputKlibFile.absolutePath, + messageCollector = messageCollector, + diagnosticsReporter = diagnosticsReporter, + jsOutputName = moduleName + ) + + if (messageCollector.hasErrors()) { + val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) + throw AssertionError("The following errors occurred serializing test klib:\n$messages") + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt index 7e1bc16283e..b8cb5edce43 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt @@ -15,10 +15,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector -import org.jetbrains.kotlin.cli.js.klib.compileModuleToAnalyzedFirWithPsi -import org.jetbrains.kotlin.cli.js.klib.generateIrForKlibSerialization -import org.jetbrains.kotlin.cli.js.klib.serializeFirKlib -import org.jetbrains.kotlin.cli.js.klib.transformFirToIr +import org.jetbrains.kotlin.cli.js.klib.* import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys @@ -205,36 +202,37 @@ abstract class AbstractJsPartialLinkageTestCase(val compilerType: CompilerType) val outputStream = ByteArrayOutputStream() val messageCollector = PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.PLAIN_FULL_PATHS, true) - val outputs = compileModuleToAnalyzedFirWithPsi( + val analyzedOutput = compileModuleToAnalyzedFirWithPsi( moduleStructure = moduleStructure, ktFiles = ktFiles, libraries = regularDependencies, friendLibraries = friendDependencies, - messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = null, lookupTracker = null ) - if (outputs != null) { - val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter) + val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter) - serializeFirKlib( - moduleStructure = moduleStructure, - firOutputs = outputs, - fir2IrActualizedResult = fir2IrActualizedResult, - outputKlibPath = klibFile.absolutePath, - messageCollector = messageCollector, - diagnosticsReporter = diagnosticsReporter, - jsOutputName = moduleName - ) - } - - if (messageCollector.hasErrors()) { + if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) { val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) throw AssertionError("The following errors occurred compiling test:\n$messages") } + serializeFirKlib( + moduleStructure = moduleStructure, + firOutputs = analyzedOutput.output, + fir2IrActualizedResult = fir2IrActualizedResult, + outputKlibPath = klibFile.absolutePath, + messageCollector = messageCollector, + diagnosticsReporter = diagnosticsReporter, + jsOutputName = moduleName + ) + + if (messageCollector.hasErrors()) { + val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) + throw AssertionError("The following errors occurred serializing test klib:\n$messages") + } } private fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Dependencies) {