[JS IR] Check fir compilation errors after checking IC next round

This commit is contained in:
Alexander Korepanov
2023-05-03 13:07:08 +02:00
committed by Space Team
parent 28b781f60a
commit e4d7897071
4 changed files with 90 additions and 74 deletions
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.cli.js
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil 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.CompilationException
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr
@@ -482,7 +482,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
friendLibraries: List<String>, friendLibraries: List<String>,
arguments: K2JSCompilerArguments, arguments: K2JSCompilerArguments,
outputKlibPath: String outputKlibPath: String
): ModulesStructure? { ): ModulesStructure {
val configuration = environmentForJS.configuration val configuration = environmentForJS.configuration
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter() val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter()
@@ -492,7 +492,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: LookupTracker.DO_NOTHING 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) configuration.getBoolean(CommonConfigurationKeys.USE_FIR) && configuration.getBoolean(CommonConfigurationKeys.USE_LIGHT_TREE)
) { ) {
val groupedSources = collectSources(configuration, environmentForJS.project, messageCollector) val groupedSources = collectSources(configuration, environmentForJS.project, messageCollector)
@@ -506,38 +506,46 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
ktSourceFiles = groupedSources.commonSources + groupedSources.platformSources, ktSourceFiles = groupedSources.commonSources + groupedSources.platformSources,
libraries = libraries, libraries = libraries,
friendLibraries = friendLibraries, friendLibraries = friendLibraries,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter, diagnosticsReporter = diagnosticsReporter,
incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER],
lookupTracker = lookupTracker, lookupTracker = lookupTracker,
) ?: return null )
} else { } else {
compileModuleToAnalyzedFirWithPsi( compileModuleToAnalyzedFirWithPsi(
moduleStructure = moduleStructure, moduleStructure = moduleStructure,
ktFiles = environmentForJS.getSourceFiles(), ktFiles = environmentForJS.getSourceFiles(),
libraries = libraries, libraries = libraries,
friendLibraries = friendLibraries, friendLibraries = friendLibraries,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter, diagnosticsReporter = diagnosticsReporter,
incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER],
lookupTracker = lookupTracker, lookupTracker = lookupTracker,
) ?: return null )
} }
// FIR2IR // FIR2IR
val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter) val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter)
if (configuration.getBoolean(CommonConfigurationKeys.INCREMENTAL_COMPILATION)) { 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() throw IncrementalNextRoundException()
} }
} }
if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) {
throw CompilationErrorException()
}
// Serialize klib // Serialize klib
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) { if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
serializeFirKlib( serializeFirKlib(
moduleStructure = moduleStructure, moduleStructure = moduleStructure,
firOutputs = outputs, firOutputs = analyzedOutput.output,
fir2IrActualizedResult = fir2IrActualizedResult, fir2IrActualizedResult = fir2IrActualizedResult,
outputKlibPath = outputKlibPath, outputKlibPath = outputKlibPath,
messageCollector = messageCollector, messageCollector = messageCollector,
@@ -55,27 +55,18 @@ inline fun <F> compileModuleToAnalyzedFir(
files: List<F>, files: List<F>,
libraries: List<String>, libraries: List<String>,
friendLibraries: List<String>, friendLibraries: List<String>,
messageCollector: MessageCollector,
diagnosticsReporter: BaseDiagnosticsCollector,
incrementalDataProvider: IncrementalDataProvider?, incrementalDataProvider: IncrementalDataProvider?,
lookupTracker: LookupTracker?, lookupTracker: LookupTracker?,
fileHasSyntaxErrors: (F) -> Boolean,
noinline isCommonSource: (F) -> Boolean, noinline isCommonSource: (F) -> Boolean,
noinline fileBelongsToModule: (F, String) -> Boolean, noinline fileBelongsToModule: (F, String) -> Boolean,
buildResolveAndCheckFir: (FirSession, List<F>) -> ModuleCompilerAnalyzedOutput, buildResolveAndCheckFir: (FirSession, List<F>) -> ModuleCompilerAnalyzedOutput,
): List<ModuleCompilerAnalyzedOutput>? { ): List<ModuleCompilerAnalyzedOutput> {
val renderDiagnosticNames = moduleStructure.compilerConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
// FIR // FIR
val extensionRegistrars = FirExtensionRegistrar.getInstances(moduleStructure.project) val extensionRegistrars = FirExtensionRegistrar.getInstances(moduleStructure.project)
val mainModuleName = moduleStructure.compilerConfiguration.get(CommonConfigurationKeys.MODULE_NAME)!! val mainModuleName = moduleStructure.compilerConfiguration.get(CommonConfigurationKeys.MODULE_NAME)!!
val escapedMainModuleName = Name.special("<$mainModuleName>") 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 binaryModuleData = BinaryModuleData.initialize(escapedMainModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices)
val dependencyList = DependencyListForCliModule.build(binaryModuleData) { val dependencyList = DependencyListForCliModule.build(binaryModuleData) {
dependencies(libraries.map { Paths.get(it).toAbsolutePath() }) dependencies(libraries.map { Paths.get(it).toAbsolutePath() })
@@ -97,40 +88,61 @@ inline fun <F> compileModuleToAnalyzedFir(
buildResolveAndCheckFir(it.session, it.files) buildResolveAndCheckFir(it.session, it.files)
} }
if (syntaxErrors || diagnosticsReporter.hasErrors) {
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(diagnosticsReporter, messageCollector, renderDiagnosticNames)
return null
}
return outputs return outputs
} }
open class AnalyzedFirOutput(val output: List<ModuleCompilerAnalyzedOutput>) {
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<ModuleCompilerAnalyzedOutput>,
private val compiledFiles: List<KtFile>
) : AnalyzedFirOutput(output) {
override fun checkSyntaxErrors(messageCollector: MessageCollector): Boolean {
return compiledFiles.fold(false) { errorsFound, file ->
AnalyzerWithCompilerReport.reportSyntaxErrors(file, messageCollector).isHasErrors or errorsFound
}
}
}
fun compileModuleToAnalyzedFirWithPsi( fun compileModuleToAnalyzedFirWithPsi(
moduleStructure: ModulesStructure, moduleStructure: ModulesStructure,
ktFiles: List<KtFile>, ktFiles: List<KtFile>,
libraries: List<String>, libraries: List<String>,
friendLibraries: List<String>, friendLibraries: List<String>,
messageCollector: MessageCollector,
diagnosticsReporter: BaseDiagnosticsCollector, diagnosticsReporter: BaseDiagnosticsCollector,
incrementalDataProvider: IncrementalDataProvider?, incrementalDataProvider: IncrementalDataProvider?,
lookupTracker: LookupTracker?, lookupTracker: LookupTracker?,
): List<ModuleCompilerAnalyzedOutput>? { ): AnalyzedFirWithPsiOutput {
return compileModuleToAnalyzedFir( val output = compileModuleToAnalyzedFir(
moduleStructure, moduleStructure,
ktFiles, ktFiles,
libraries, libraries,
friendLibraries, friendLibraries,
messageCollector,
diagnosticsReporter,
incrementalDataProvider, incrementalDataProvider,
lookupTracker, lookupTracker,
fileHasSyntaxErrors = { AnalyzerWithCompilerReport.reportSyntaxErrors(it, messageCollector).isHasErrors },
isCommonSource = isCommonSourceForPsi, isCommonSource = isCommonSourceForPsi,
fileBelongsToModule = fileBelongsToModuleForPsi, fileBelongsToModule = fileBelongsToModuleForPsi,
buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFir = { session, files ->
buildResolveAndCheckFirFromKtFiles(session, files, diagnosticsReporter) buildResolveAndCheckFirFromKtFiles(session, files, diagnosticsReporter)
}, },
) )
return AnalyzedFirWithPsiOutput(output, ktFiles)
} }
fun compileModulesToAnalyzedFirWithLightTree( fun compileModulesToAnalyzedFirWithLightTree(
@@ -139,27 +151,24 @@ fun compileModulesToAnalyzedFirWithLightTree(
ktSourceFiles: List<KtSourceFile>, ktSourceFiles: List<KtSourceFile>,
libraries: List<String>, libraries: List<String>,
friendLibraries: List<String>, friendLibraries: List<String>,
messageCollector: MessageCollector,
diagnosticsReporter: BaseDiagnosticsCollector, diagnosticsReporter: BaseDiagnosticsCollector,
incrementalDataProvider: IncrementalDataProvider?, incrementalDataProvider: IncrementalDataProvider?,
lookupTracker: LookupTracker?, lookupTracker: LookupTracker?,
): List<ModuleCompilerAnalyzedOutput>? { ): AnalyzedFirOutput {
return compileModuleToAnalyzedFir( val output = compileModuleToAnalyzedFir(
moduleStructure, moduleStructure,
ktSourceFiles, ktSourceFiles,
libraries, libraries,
friendLibraries, friendLibraries,
messageCollector,
diagnosticsReporter,
incrementalDataProvider, incrementalDataProvider,
lookupTracker, lookupTracker,
fileHasSyntaxErrors = { false },
isCommonSource = { groupedSources.isCommonSourceForLt(it) }, isCommonSource = { groupedSources.isCommonSourceForLt(it) },
fileBelongsToModule = { file, it -> groupedSources.fileBelongsToModuleForLt(file, it) }, fileBelongsToModule = { file, it -> groupedSources.fileBelongsToModuleForLt(file, it) },
buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFir = { session, files ->
buildResolveAndCheckFirViaLightTree(session, files, diagnosticsReporter, null) buildResolveAndCheckFirViaLightTree(session, files, diagnosticsReporter, null)
}, },
) )
return AnalyzedFirOutput(output)
} }
fun transformFirToIr( fun transformFirToIr(
@@ -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.compileModuleToAnalyzedFirWithPsi
import org.jetbrains.kotlin.cli.js.klib.serializeFirKlib import org.jetbrains.kotlin.cli.js.klib.serializeFirKlib
import org.jetbrains.kotlin.cli.js.klib.transformFirToIr import org.jetbrains.kotlin.cli.js.klib.transformFirToIr
import org.jetbrains.kotlin.codegen.ProjectInfo
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.ir.backend.js.MainModule import org.jetbrains.kotlin.ir.backend.js.MainModule
@@ -64,34 +63,36 @@ abstract class FirAbstractInvalidationTest(
friendDependenciesPaths = friendLibraries friendDependenciesPaths = friendLibraries
) )
val outputs = compileModuleToAnalyzedFirWithPsi( val analyzedOutput = compileModuleToAnalyzedFirWithPsi(
moduleStructure = moduleStructure, moduleStructure = moduleStructure,
ktFiles = sourceFiles, ktFiles = sourceFiles,
libraries = libraries, libraries = libraries,
friendLibraries = friendLibraries, friendLibraries = friendLibraries,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter, diagnosticsReporter = diagnosticsReporter,
incrementalDataProvider = null, incrementalDataProvider = null,
lookupTracker = null, lookupTracker = null,
) )
if (outputs != null) { val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter)
val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter)
serializeFirKlib( if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) {
moduleStructure = moduleStructure,
firOutputs = outputs,
fir2IrActualizedResult = fir2IrActualizedResult,
outputKlibPath = outputKlibFile.absolutePath,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter,
jsOutputName = moduleName
)
}
if (messageCollector.hasErrors()) {
val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8"))
throw AssertionError("The following errors occurred compiling test:\n$messages") 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")
}
} }
} }
@@ -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.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.js.klib.compileModuleToAnalyzedFirWithPsi import org.jetbrains.kotlin.cli.js.klib.*
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.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
@@ -205,36 +202,37 @@ abstract class AbstractJsPartialLinkageTestCase(val compilerType: CompilerType)
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
val messageCollector = PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.PLAIN_FULL_PATHS, true) val messageCollector = PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.PLAIN_FULL_PATHS, true)
val outputs = compileModuleToAnalyzedFirWithPsi( val analyzedOutput = compileModuleToAnalyzedFirWithPsi(
moduleStructure = moduleStructure, moduleStructure = moduleStructure,
ktFiles = ktFiles, ktFiles = ktFiles,
libraries = regularDependencies, libraries = regularDependencies,
friendLibraries = friendDependencies, friendLibraries = friendDependencies,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter, diagnosticsReporter = diagnosticsReporter,
incrementalDataProvider = null, incrementalDataProvider = null,
lookupTracker = null lookupTracker = null
) )
if (outputs != null) { val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter)
val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter)
serializeFirKlib( if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) {
moduleStructure = moduleStructure,
firOutputs = outputs,
fir2IrActualizedResult = fir2IrActualizedResult,
outputKlibPath = klibFile.absolutePath,
messageCollector = messageCollector,
diagnosticsReporter = diagnosticsReporter,
jsOutputName = moduleName
)
}
if (messageCollector.hasErrors()) {
val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8")) val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8"))
throw AssertionError("The following errors occurred compiling test:\n$messages") 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) { private fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Dependencies) {