[FIR & IR] Implement JS MPP test infrastructure
^KT-55295 Fixed
This commit is contained in:
committed by
Space Team
parent
e42efe1ee6
commit
d401ff7b09
+1
-1
@@ -35,6 +35,6 @@ object IrActualizer {
|
||||
}
|
||||
|
||||
private fun mergeIrFragments(mainFragment: IrModuleFragment, dependentFragments: List<IrModuleFragment>) {
|
||||
mainFragment.files.addAll(dependentFragments.flatMap { it.files })
|
||||
mainFragment.files.addAll(0, dependentFragments.flatMap { it.files })
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND_K1: ANY
|
||||
// IGNORE_BACKEND_K2: JS_IR, NATIVE
|
||||
// IGNORE_BACKEND_K2: NATIVE
|
||||
|
||||
// MODULE: common
|
||||
// FILE: common.kt
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// IGNORE_BACKEND_K1: JS, JS_IR, JS_IR_ES6
|
||||
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
|
||||
// MODULE: common
|
||||
// TARGET_PLATFORM: Common
|
||||
// FILE: common.kt
|
||||
|
||||
expect fun func(): String
|
||||
|
||||
expect var prop: String
|
||||
|
||||
fun test(): String {
|
||||
prop = "K"
|
||||
return func() + prop
|
||||
}
|
||||
|
||||
// MODULE: js()()(common)
|
||||
// TARGET_PLATFORM: JS
|
||||
// FILE: main.kt
|
||||
|
||||
actual fun func(): String = "O"
|
||||
|
||||
actual var prop: String = "!"
|
||||
|
||||
fun box() = test()
|
||||
+6
-2
@@ -30,14 +30,18 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
|
||||
abstract val irPluginContext: IrPluginContext
|
||||
|
||||
data class JsIrBackendInput(
|
||||
override val irModuleFragment: IrModuleFragment,
|
||||
val mainModuleFragment: IrModuleFragment,
|
||||
val dependentModuleFragments: List<IrModuleFragment>,
|
||||
override val irPluginContext: IrPluginContext,
|
||||
val sourceFiles: List<KtSourceFile>,
|
||||
val icData: List<KotlinFileSerializedData>,
|
||||
val expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>, // TODO: abstract from descriptors
|
||||
val hasErrors: Boolean,
|
||||
val serializeSingleFile: (KtSourceFile) -> ProtoBuf.PackageFragment
|
||||
) : IrBackendInput()
|
||||
) : IrBackendInput() {
|
||||
override val irModuleFragment: IrModuleFragment
|
||||
get() = mainModuleFragment
|
||||
}
|
||||
|
||||
data class JvmIrBackendInput(
|
||||
val state: GenerationState,
|
||||
|
||||
+1
@@ -105,6 +105,7 @@ class ClassicFrontend2IrConverter(
|
||||
|
||||
return IrBackendInput.JsIrBackendInput(
|
||||
moduleFragment,
|
||||
dependentModuleFragments = emptyList(),
|
||||
pluginContext,
|
||||
sourceFiles.map(::KtPsiSourceFile),
|
||||
icData,
|
||||
|
||||
+59
-37
@@ -5,26 +5,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.frontend.fir
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceFile
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
|
||||
import org.jetbrains.kotlin.fir.FirAnalyzerFacade
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.Fir2IrJvmSpecialAnnotationSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.serialization.FirElementAwareSerializableStringTable
|
||||
import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
|
||||
import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
|
||||
@@ -33,8 +31,8 @@ import org.jetbrains.kotlin.ir.backend.js.JsFactories
|
||||
import org.jetbrains.kotlin.ir.backend.js.getSerializedData
|
||||
import org.jetbrains.kotlin.ir.backend.js.incrementalDataProvider
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
|
||||
import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
@@ -59,34 +57,67 @@ class Fir2IrJsResultsConverter(
|
||||
module: TestModule,
|
||||
inputArtifact: FirOutputArtifact
|
||||
): IrBackendInput {
|
||||
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
|
||||
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
|
||||
val fir2IrExtensions = Fir2IrExtensions.Default
|
||||
val firFiles = inputArtifact.allFirFiles.values
|
||||
val (irModuleFragment, components, pluginContext) =
|
||||
inputArtifact.partsForDependsOnModules.last().firAnalyzerFacade.convertToJsIr(firFiles, fir2IrExtensions, module, configuration, testServices)
|
||||
lateinit var mainIrPart: IrModuleFragment
|
||||
val dependentIrParts = mutableListOf<IrModuleFragment>()
|
||||
val sourceFiles = mutableListOf<KtSourceFile>()
|
||||
val firFilesAndComponentsBySourceFile = mutableMapOf<KtSourceFile, Pair<FirFile, Fir2IrComponents>>()
|
||||
lateinit var mainPluginContext: IrPluginContext
|
||||
var irBuiltIns: IrBuiltInsOverFir? = null
|
||||
|
||||
val sourceFiles = firFiles.mapNotNull { it.sourceFile }
|
||||
val firFilesBySourceFile = firFiles.associateBy { it.sourceFile }
|
||||
val commonMemberStorage = Fir2IrCommonMemberStorage(
|
||||
generateSignatures = false,
|
||||
signatureComposerCreator = null,
|
||||
manglerCreator = { FirJvmKotlinMangler() } // TODO: replace with potentially simpler JS version
|
||||
)
|
||||
|
||||
for ((index, part) in inputArtifact.partsForDependsOnModules.withIndex()) {
|
||||
val (irModuleFragment, components, pluginContext) =
|
||||
part.firAnalyzerFacade.convertToJsIr(
|
||||
part.firFiles.values,
|
||||
fir2IrExtensions = Fir2IrExtensions.Default,
|
||||
module,
|
||||
configuration,
|
||||
testServices,
|
||||
commonMemberStorage,
|
||||
irBuiltIns
|
||||
)
|
||||
irBuiltIns = components.irBuiltIns
|
||||
mainPluginContext = pluginContext
|
||||
|
||||
if (index < inputArtifact.partsForDependsOnModules.size - 1) {
|
||||
dependentIrParts.add(irModuleFragment)
|
||||
} else {
|
||||
mainIrPart = irModuleFragment
|
||||
}
|
||||
|
||||
sourceFiles.addAll(part.firFiles.mapNotNull { it.value.sourceFile })
|
||||
|
||||
for (firFile in part.firFiles.values) {
|
||||
firFilesAndComponentsBySourceFile[firFile.sourceFile!!] = firFile to components
|
||||
}
|
||||
}
|
||||
|
||||
val icData = configuration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList()
|
||||
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||
val metadataVersion = configuration.metadataVersion(module.languageVersionSettings.languageVersion)
|
||||
|
||||
// At this point, checkers will already have been run by a previous test step. `runCheckers` returns the cached diagnostics map.
|
||||
val diagnosticsMap = inputArtifact.partsForDependsOnModules.last().firAnalyzerFacade.runCheckers()
|
||||
val diagnosticsMap = inputArtifact.partsForDependsOnModules.fold(mutableMapOf<FirFile, List<KtDiagnostic>>()) { result, part ->
|
||||
result.also { it.putAll(part.firAnalyzerFacade.runCheckers()) }
|
||||
}
|
||||
val hasErrors = diagnosticsMap.any { entry -> entry.value.any { it.severity == Severity.ERROR } }
|
||||
|
||||
return IrBackendInput.JsIrBackendInput(
|
||||
irModuleFragment,
|
||||
pluginContext,
|
||||
mainIrPart,
|
||||
dependentIrParts,
|
||||
mainPluginContext,
|
||||
sourceFiles,
|
||||
icData,
|
||||
expectDescriptorToSymbol,
|
||||
hasErrors,
|
||||
configuration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList(),
|
||||
expectDescriptorToSymbol = mutableMapOf(),
|
||||
hasErrors = hasErrors
|
||||
) { file ->
|
||||
val firFile = firFilesBySourceFile[file] ?: error("cannot find FIR file by source file ${file.name} (${file.path})")
|
||||
val (firFile, components) = firFilesAndComponentsBySourceFile[file]
|
||||
?: error("cannot find FIR file by source file ${file.name} (${file.path})")
|
||||
serializeSingleFirFile(
|
||||
firFile,
|
||||
components.session,
|
||||
@@ -103,26 +134,17 @@ fun AbstractFirAnalyzerFacade.convertToJsIr(
|
||||
fir2IrExtensions: Fir2IrExtensions,
|
||||
module: TestModule,
|
||||
configuration: CompilerConfiguration,
|
||||
testServices: TestServices
|
||||
testServices: TestServices,
|
||||
commonMemberStorage: Fir2IrCommonMemberStorage,
|
||||
irBuiltIns: IrBuiltInsOverFir?
|
||||
): Fir2IrResult {
|
||||
this as FirAnalyzerFacade
|
||||
val commonFirFiles = session.moduleData.dependsOnDependencies
|
||||
.map { it.session }
|
||||
.filter { it.kind == FirSession.Kind.Source }
|
||||
.flatMap { (it.firProvider as FirProviderImpl).getAllFirFiles() }
|
||||
|
||||
// TODO: consider avoiding repeated libraries resolution
|
||||
val libraries = resolveJsLibraries(module, testServices, configuration)
|
||||
val (dependencies, builtIns) = loadResolvedLibraries(libraries, configuration.languageVersionSettings, testServices)
|
||||
|
||||
val commonMemberStorage = Fir2IrCommonMemberStorage(
|
||||
generateSignatures = false,
|
||||
signatureComposerCreator = null,
|
||||
manglerCreator = { FirJvmKotlinMangler() } // TODO: replace with potentially simpler JS version
|
||||
)
|
||||
|
||||
return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded(
|
||||
session, scopeSession, firFiles + commonFirFiles,
|
||||
session, scopeSession, firFiles.toList(),
|
||||
languageVersionSettings,
|
||||
fir2IrExtensions,
|
||||
JsManglerIr, IrFactoryImpl,
|
||||
@@ -132,7 +154,7 @@ fun AbstractFirAnalyzerFacade.convertToJsIr(
|
||||
generateSignatures = false,
|
||||
kotlinBuiltIns = builtIns ?: DefaultBuiltIns.Instance, // TODO: consider passing externally,
|
||||
commonMemberStorage = commonMemberStorage,
|
||||
initializedIrBuiltIns = null
|
||||
initializedIrBuiltIns = irBuiltIns
|
||||
).also {
|
||||
(it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = dependencies }
|
||||
}
|
||||
|
||||
+2
-2
@@ -150,8 +150,8 @@ open class FirFrontendFacade(
|
||||
regularModules,
|
||||
dependsOnModules,
|
||||
friendModules,
|
||||
module.targetPlatform,
|
||||
module.targetPlatform.getAnalyzerServices()
|
||||
mainModule.targetPlatform,
|
||||
mainModule.targetPlatform.getAnalyzerServices()
|
||||
)
|
||||
|
||||
moduleInfoProvider.registerModuleData(module, moduleData)
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
|
||||
val inferMainModule = JsEnvironmentConfigurationDirectives.INFER_MAIN_MODULE in testServices.moduleStructure.allDirectives
|
||||
return when {
|
||||
inferMainModule -> modules.last()
|
||||
else -> modules.singleOrNull { it.name == ModuleStructureExtractor.DEFAULT_MODULE_NAME } ?: modules.single()
|
||||
else -> modules.singleOrNull { it.name == ModuleStructureExtractor.DEFAULT_MODULE_NAME } ?: modules.last()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-7
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.services.impl
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.js.JsPlatforms
|
||||
@@ -351,13 +352,18 @@ class ModuleStructureExtractorImpl(
|
||||
languageVersionSettings = currentModuleLanguageVersionSettingsBuilder.build()
|
||||
)
|
||||
modules += testModule
|
||||
additionalSourceProviders.flatMapTo(filesOfCurrentModule) { additionalSourceProvider ->
|
||||
additionalSourceProvider.produceAdditionalFiles(
|
||||
globalDirectives ?: RegisteredDirectives.Empty,
|
||||
testModule
|
||||
).also { additionalFiles ->
|
||||
require(additionalFiles.all { it.isAdditional }) {
|
||||
"Files produced by ${additionalSourceProvider::class.qualifiedName} should have flag `isAdditional = true`"
|
||||
if (testModule.frontendKind != FrontendKinds.FIR ||
|
||||
!testModule.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects) ||
|
||||
testModule.dependsOnDependencies.isEmpty()
|
||||
) {
|
||||
additionalSourceProviders.flatMapTo(filesOfCurrentModule) { additionalSourceProvider ->
|
||||
additionalSourceProvider.produceAdditionalFiles(
|
||||
globalDirectives ?: RegisteredDirectives.Empty,
|
||||
testModule
|
||||
).also { additionalFiles ->
|
||||
require(additionalFiles.all { it.isAdditional }) {
|
||||
"Files produced by ${additionalSourceProvider::class.qualifiedName} should have flag `isAdditional = true`"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,16 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.test.converters
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsFactories
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
|
||||
import org.jetbrains.kotlin.ir.backend.js.resolverLogger
|
||||
import org.jetbrains.kotlin.ir.backend.js.serializeModuleIntoKlib
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.js.test.utils.JsIrIncrementalDataProvider
|
||||
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
|
||||
@@ -23,6 +28,7 @@ import org.jetbrains.kotlin.test.frontend.fir.getAllJsDependenciesPaths
|
||||
import org.jetbrains.kotlin.test.frontend.fir.resolveJsLibraries
|
||||
import org.jetbrains.kotlin.test.model.ArtifactKinds
|
||||
import org.jetbrains.kotlin.test.model.BinaryArtifacts
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
||||
@@ -55,6 +61,10 @@ class FirJsKlibBackendFacade(
|
||||
val libraries = resolveJsLibraries(module, testServices, configuration)
|
||||
|
||||
if (firstTimeCompilation) {
|
||||
if (module.frontendKind == FrontendKinds.FIR && module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
|
||||
IrActualizer.actualize(inputArtifact.mainModuleFragment, inputArtifact.dependentModuleFragments)
|
||||
}
|
||||
|
||||
serializeModuleIntoKlib(
|
||||
configuration[CommonConfigurationKeys.MODULE_NAME]!!,
|
||||
configuration,
|
||||
|
||||
+6
@@ -23040,6 +23040,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualMemberLink.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualSimpleJs.kt")
|
||||
public void testExpectActualSimpleJs() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualSimpleJs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualTypealiasLink.kt")
|
||||
public void testExpectActualTypealiasLink() throws Exception {
|
||||
|
||||
+6
@@ -23040,6 +23040,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualMemberLink.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualSimpleJs.kt")
|
||||
public void testExpectActualSimpleJs() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualSimpleJs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualTypealiasLink.kt")
|
||||
public void testExpectActualTypealiasLink() throws Exception {
|
||||
|
||||
+6
@@ -23040,6 +23040,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualMemberLink.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualSimpleJs.kt")
|
||||
public void testExpectActualSimpleJs() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/multiModule/expectActualSimpleJs.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectActualTypealiasLink.kt")
|
||||
public void testExpectActualTypealiasLink() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user