FIR JS: enable full JS box tests with FIR

This commit is contained in:
Ilya Chernikov
2022-07-06 13:01:03 +02:00
parent 30df65c321
commit fa0cda6236
17 changed files with 343 additions and 69 deletions
@@ -50,7 +50,7 @@ class KlibBasedSymbolProvider(
}
override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> {
val packageStringName = packageFqName.asString()
val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString()
if (packageStringName !in fragmentNameList) {
return emptyList()
@@ -28,8 +28,8 @@ abstract class FirSerializerExtension {
open fun shouldSerializeTypeAlias(typeAlias: FirTypeAlias): Boolean = true
open fun shouldUseTypeTable(): Boolean = false
open fun shouldUseNormalizedVisibility(): Boolean = false
open fun shouldSerializeFunction(function: FirFunction): Boolean = false
open fun shouldSerializeProperty(property: FirProperty): Boolean = false
abstract fun shouldSerializeFunction(function: FirFunction): Boolean
abstract fun shouldSerializeProperty(property: FirProperty): Boolean
open fun serializePackage(packageFqName: FqName, proto: ProtoBuf.Package.Builder) {
}
@@ -6,8 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.backend.common.serialization.metadata.buildKlibPackageFragment
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
@@ -19,14 +18,11 @@ import org.jetbrains.kotlin.fir.serialization.FirSerializerExtension
import org.jetbrains.kotlin.fir.serialization.TypeApproximatorForMetadataSerializer
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.SerializableStringTable
fun serializeSingleFirFile(file: FirFile, session: FirSession, scopeSession: ScopeSession, configuration: CompilerConfiguration): ProtoBuf.PackageFragment {
val serializerExtension = FirKLibSerializerExtension(
session,
configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!,
FirElementAwareSerializableStringTable()
)
fun serializeSingleFirFile(file: FirFile, session: FirSession, scopeSession: ScopeSession, metadataVersion: BinaryVersion): ProtoBuf.PackageFragment {
val serializerExtension = FirKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable())
val approximator = TypeApproximatorForMetadataSerializer(session)
val packageSerializer = FirElementSerializer.createTopLevel(session, scopeSession, serializerExtension, approximator)
@@ -36,14 +32,15 @@ fun serializeSingleFirFile(file: FirFile, session: FirSession, scopeSession: Sco
val packageProto = packageSerializer.packagePartProto(file.packageFqName, file).build()
// TODO: filter out expects
val classifiers = file.declarations.filterIsInstance<FirClass>().sortedBy { it.classId.asFqNameString() }
fun List<FirDeclaration>.makeClassesProtoWithNested(): List<Pair<ProtoBuf.Class, Int>> =
// TODO: filter out expects
filterIsInstance<FirClass>().sortedBy { it.classId.asFqNameString() }.flatMap {
val classSerializer = FirElementSerializer.create(session, scopeSession, it, serializerExtension, null, approximator)
val index = classSerializer.stringTable.getFqNameIndex(it)
listOf(classSerializer.classProto(it).build() to index) + it.declarations.makeClassesProtoWithNested()
}
val classesProto = classifiers.map {
val classSerializer = FirElementSerializer.create(session, scopeSession, it, serializerExtension, null, approximator)
val index = classSerializer.stringTable.getFqNameIndex(it)
classSerializer.classProto(it).build() to index
}
val classesProto = file.declarations.makeClassesProtoWithNested()
val hasTopLevelDeclarations = file.declarations.any {
it is FirProperty || it is FirSimpleFunction || it is FirTypeAlias
@@ -62,6 +59,12 @@ class FirKLibSerializerExtension(
override val session: FirSession,
override val metadataVersion: BinaryVersion,
override val stringTable: FirElementAwareSerializableStringTable
) : FirSerializerExtension()
) : FirSerializerExtension() {
override fun shouldSerializeFunction(function: FirFunction): Boolean = true
class FirElementAwareSerializableStringTable() : FirElementAwareStringTable, SerializableStringTable()
override fun shouldSerializeProperty(property: FirProperty): Boolean = true
}
class FirElementAwareSerializableStringTable() : FirElementAwareStringTable, SerializableStringTable() {
override fun getLocalClassIdReplacement(firClass: FirClass): ClassId? = ClassId.topLevel(StandardNames.FqNames.any.toSafe())
}
@@ -6,20 +6,19 @@
package org.jetbrains.kotlin.test.services
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.library.KotlinLibrary
class JsLibraryProvider(private val testServices: TestServices) : TestService {
private val descriptorToLibrary = mutableMapOf<ModuleDescriptor, KotlinLibrary>()
private val stdlibPathToDescriptor = mutableMapOf<String, ModuleDescriptorImpl>()
private val stdlibPathToDescriptor = mutableMapOf<String, ModuleDescriptor>()
fun getDescriptorByPath(path: String): ModuleDescriptorImpl {
fun getDescriptorByPath(path: String): ModuleDescriptor {
return stdlibPathToDescriptor[path] ?: testServices.assertions.fail {
"There is no library with path $path"
}
}
fun setDescriptorAndLibraryByName(name: String, descriptor: ModuleDescriptorImpl, library: KotlinLibrary) {
fun setDescriptorAndLibraryByName(name: String, descriptor: ModuleDescriptor, library: KotlinLibrary) {
stdlibPathToDescriptor[name] = descriptor
descriptorToLibrary[descriptor] = library
}
@@ -40,7 +39,7 @@ class JsLibraryProvider(private val testServices: TestServices) : TestService {
}
}
fun getOrCreateStdlibByPath(path: String, create: (String) -> Pair<ModuleDescriptorImpl, KotlinLibrary>): ModuleDescriptorImpl {
fun getOrCreateStdlibByPath(path: String, create: (String) -> Pair<ModuleDescriptor, KotlinLibrary>): ModuleDescriptor {
return stdlibPathToDescriptor.getOrPut(path) {
create(path).let {
descriptorToLibrary += it
@@ -15,9 +15,9 @@ import org.jetbrains.kotlin.test.services.getOrCreateTempDirectory
import java.io.File
class IrInterpreterDumpHandler(testServices: TestServices) : JvmBinaryArtifactHandler(testServices) {
private fun getDump(): Pair<File, File>? {
private fun getDump(module: TestModule): Pair<File, File>? {
val dumpDirectory = testServices.getOrCreateTempDirectory(PhasedIrDumpHandler.DUMPED_IR_FOLDER_NAME)
val dumpFiles = dumpDirectory.resolve(FirModuleDescriptor.FIR_MODULE_NAME.asString()).listFiles()
val dumpFiles = dumpDirectory.resolve(module.name).listFiles()
val before = dumpFiles?.single { it.name.contains(PhasedIrDumpHandler.BEFORE_PREFIX) } ?: return null
val after = dumpFiles.single { it.name.contains(PhasedIrDumpHandler.AFTER_PREFIX) } ?: return null
return Pair(before, after)
@@ -41,7 +41,7 @@ class IrInterpreterDumpHandler(testServices: TestServices) : JvmBinaryArtifactHa
override fun processModule(module: TestModule, info: BinaryArtifacts.Jvm) {
if (CodegenTestDirectives.DUMP_IR_FOR_GIVEN_PHASES !in module.directives) return
val (before, after) = getDump() ?: testServices.assertions.fail { "Cannot find BEFORE and AFTER lowering files" }
val (before, after) = getDump(module) ?: testServices.assertions.fail { "Cannot find BEFORE and AFTER lowering files" }
val beforeText = before.readText()
val afterText = after.readText()
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.context.withModule
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDependenciesImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
@@ -93,6 +94,7 @@ class ClassicFrontendFacade(
val ktFiles = ktFilesMap.values.toList()
setupJavacIfNeeded(module, ktFiles, configuration)
@Suppress("UNCHECKED_CAST")
val analysisResult = performResolve(
module,
project,
@@ -100,9 +102,9 @@ class ClassicFrontendFacade(
packagePartProviderFactory,
ktFiles,
compilerEnvironment = multiplatformAnalysisConfiguration.getCompilerEnvironment(module),
dependencyDescriptors = multiplatformAnalysisConfiguration.getDependencyDescriptors(module),
friendsDescriptors = multiplatformAnalysisConfiguration.getFriendDescriptors(module),
dependsOnDescriptors = multiplatformAnalysisConfiguration.getDependsOnDescriptors(module)
dependencyDescriptors = multiplatformAnalysisConfiguration.getDependencyDescriptors(module) as List<ModuleDescriptorImpl>,
friendsDescriptors = multiplatformAnalysisConfiguration.getFriendDescriptors(module) as List<ModuleDescriptorImpl>,
dependsOnDescriptors = multiplatformAnalysisConfiguration.getDependsOnDescriptors(module) as List<ModuleDescriptorImpl>
)
moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor)
return ClassicFrontendOutputArtifact(
@@ -251,7 +253,7 @@ class ClassicFrontendFacade(
)
}
private fun loadKlib(names: List<String>, configuration: CompilerConfiguration): List<ModuleDescriptorImpl> {
private fun loadKlib(names: List<String>, configuration: CompilerConfiguration): List<ModuleDescriptor> {
val resolvedLibraries = jsResolveLibraries(
names,
configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(),
@@ -261,8 +263,8 @@ class ClassicFrontendFacade(
var builtInsModule: KotlinBuiltIns? = null
val dependencies = mutableListOf<ModuleDescriptorImpl>()
return resolvedLibraries.zip(names).map { (resolvedLibrary, klibPath) ->
testServices.jsLibraryProvider.getOrCreateStdlibByPath(klibPath) {
return resolvedLibraries.map { resolvedLibrary ->
testServices.jsLibraryProvider.getOrCreateStdlibByPath(resolvedLibrary.library.libraryName) {
val storageManager = LockBasedStorageManager("ModulesStructure")
val isBuiltIns = resolvedLibrary.library.unresolvedDependencies.isEmpty()
@@ -290,8 +292,8 @@ class ClassicFrontendFacade(
configuration: CompilerConfiguration,
compilerEnvironment: TargetEnvironment,
files: List<KtFile>,
dependencyDescriptors: List<ModuleDescriptorImpl>,
friendsDescriptors: List<ModuleDescriptorImpl>,
dependencyDescriptors: List<ModuleDescriptor>,
friendsDescriptors: List<ModuleDescriptor>,
): AnalysisResult {
val runtimeKlibsNames = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices)
val runtimeKlibs = loadKlib(runtimeKlibsNames, configuration)
@@ -15,16 +15,15 @@ import org.jetbrains.kotlin.test.model.TestModule
class ModuleDescriptorProvider(
private val testServices: TestServices
) : TestService {
private val moduleDescriptorByModule = mutableMapOf<TestModule, ModuleDescriptorImpl>()
private val moduleDescriptorByModule = mutableMapOf<TestModule, ModuleDescriptor>()
fun getModuleDescriptor(testModule: TestModule): ModuleDescriptorImpl {
fun getModuleDescriptor(testModule: TestModule): ModuleDescriptor {
return moduleDescriptorByModule[testModule] ?: testServices.assertions.fail {
"Module descriptor for module ${testModule.name} not found"
}
}
fun replaceModuleDescriptorForModule(testModule: TestModule, moduleDescriptor: ModuleDescriptor) {
require(moduleDescriptor is ModuleDescriptorImpl)
moduleDescriptorByModule[testModule] = moduleDescriptor
}
}
@@ -42,9 +42,9 @@ internal fun MultiplatformAnalysisConfiguration(testServices: TestServices): Mul
internal interface MultiplatformAnalysisConfiguration {
fun getCompilerEnvironment(module: TestModule): TargetEnvironment
fun getKtFilesForForSourceFiles(project: Project, module: TestModule): Map<TestFile, KtFile>
fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl>
fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl>
fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl>
fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptor>
fun getFriendDescriptors(module: TestModule): List<ModuleDescriptor>
fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptor>
}
/**
@@ -63,18 +63,18 @@ internal class MultiplatformSeparateAnalysisConfiguration(
return CompilerEnvironment
}
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptor> {
return getDescriptors(
module.allDependencies - module.dependsOnDependencies.toSet(),
dependencyProvider, moduleDescriptorProvider
)
}
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptor> {
return emptyList()
}
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptor> {
return getDescriptors(
module.friendDependencies, dependencyProvider, moduleDescriptorProvider
)
@@ -121,7 +121,7 @@ internal class MultiplatformCompositeAnalysisConfiguration(
return sourceFileProvider.getKtFilesForSourceFiles(module.files, project)
}
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptor> {
// Transitive dependsOn descriptors should also be returned as dependencies
val allDependsOnDependencies = module.dependsOnDependencies.closure(preserveOrder = true) { dependsOnDependency ->
dependencyProvider.getTestModule(dependsOnDependency.moduleName).dependsOnDependencies
@@ -130,11 +130,11 @@ internal class MultiplatformCompositeAnalysisConfiguration(
return getDescriptors(allDependencies, dependencyProvider, moduleDescriptorProvider)
}
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptor> {
return getDescriptors(module.dependsOnDependencies, dependencyProvider, moduleDescriptorProvider)
}
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptor> {
return getDescriptors(module.friendDependencies, dependencyProvider, moduleDescriptorProvider)
}
}
@@ -177,7 +177,7 @@ private fun getDescriptors(
dependencies: Iterable<DependencyDescription>,
dependencyProvider: DependencyProvider,
moduleDescriptorProvider: ModuleDescriptorProvider
): List<ModuleDescriptorImpl> {
): List<ModuleDescriptor> {
return dependencies.filter { it.kind == DependencyKind.Source }
.map { dependencyDescription -> dependencyProvider.getTestModule(dependencyDescription.moduleName) }
.map { dependencyModule -> moduleDescriptorProvider.getModuleDescriptor(dependencyModule) }
@@ -0,0 +1,157 @@
/*
* Copyright 2010-2020 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.test.frontend.fir
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys
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.fir.*
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrResult
import org.jetbrains.kotlin.fir.backend.Fir2IrVisibilityConverter
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.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
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.JsManglerDesc
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
import org.jetbrains.kotlin.ir.backend.js.serializeSingleFirFile
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.jsLibraryProvider
class Fir2IrJsResultsConverter(
testServices: TestServices
) : Frontend2BackendConverter<FirOutputArtifact, IrBackendInput>(
testServices,
FrontendKinds.FIR,
BackendKinds.IrBackend
) {
override fun transform(
module: TestModule,
inputArtifact: FirOutputArtifact
): IrBackendInput {
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
val fir2IrExtensions = Fir2IrExtensions.Default
val firFiles = inputArtifact.allFirFiles.values
val (irModuleFragment, components) =
inputArtifact.firAnalyzerFacade.convertToJsIr(firFiles, fir2IrExtensions, module, configuration, testServices)
val sourceFiles = firFiles.mapNotNull { it.sourceFile }
val firFilesBySourceFile = firFiles.associateBy { it.sourceFile }
val icData = configuration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList()
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val metadataVersion =
configuration.get(CommonConfigurationKeys.METADATA_VERSION)
?: GenerationState.LANGUAGE_TO_METADATA_VERSION.getValue(module.languageVersionSettings.languageVersion)
return IrBackendInput.JsIrBackendInput(
irModuleFragment,
sourceFiles,
icData,
expectDescriptorToSymbol,
hasErrors = false // TODO: implement error check
) { file ->
val firFile = firFilesBySourceFile[file] ?: error("cannot find FIR file by source file ${file.name} (${file.path})")
serializeSingleFirFile(firFile, components.session, components.scopeSession, metadataVersion)
}
}
}
fun AbstractFirAnalyzerFacade.convertToJsIr(
firFiles: Collection<FirFile>,
fir2IrExtensions: Fir2IrExtensions,
module: TestModule,
configuration: CompilerConfiguration,
testServices: TestServices
): Fir2IrResult {
this as FirAnalyzerFacade
val signaturer = IdSignatureDescriptor(JsManglerDesc)
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)
return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded(
session, scopeSession, firFiles + commonFirFiles,
languageVersionSettings, signaturer,
fir2IrExtensions,
FirJvmKotlinMangler(session), // TODO: replace with potentially simpler JS version
JsManglerIr, IrFactoryImpl,
Fir2IrVisibilityConverter.Default,
Fir2IrJvmSpecialAnnotationSymbolProvider(), // TODO: replace with appropriate (probably empty) implementation
irGeneratorExtensions,
generateSignatures = false,
kotlinBuiltIns = builtIns ?: DefaultBuiltIns.Instance // TODO: consider passing externally
).also {
(it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = dependencies }
}
}
private fun loadResolvedLibraries(
resolvedLibraries: List<KotlinResolvedLibrary>,
languageVersionSettings: LanguageVersionSettings,
testServices: TestServices
): Pair<List<ModuleDescriptor>, KotlinBuiltIns?> {
var builtInsModule: KotlinBuiltIns? = null
val dependencies = mutableListOf<ModuleDescriptorImpl>()
return resolvedLibraries.map { resolvedLibrary ->
// resolvedLibrary.library.libraryName in fact resolves to (modified) file path, which is confising and maybe should be refactored
testServices.jsLibraryProvider.getOrCreateStdlibByPath(resolvedLibrary.library.libraryName) {
// TODO: check safety of the approach of creating a separate storage manager per library
val storageManager = LockBasedStorageManager("ModulesStructure")
val moduleDescriptor = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
resolvedLibrary.library,
languageVersionSettings,
storageManager,
builtInsModule,
packageAccessHandler = null,
lookupTracker = LookupTracker.DO_NOTHING
)
dependencies += moduleDescriptor
moduleDescriptor.setDependencies(ArrayList(dependencies))
Pair(moduleDescriptor, resolvedLibrary.library)
}.also {
val isBuiltIns = resolvedLibrary.library.unresolvedDependencies.isEmpty()
if (isBuiltIns) builtInsModule = it.builtIns
}
} to builtInsModule
}
@@ -83,7 +83,9 @@ class FirFrontendFacade(
testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList()
}
val moduleName = Name.identifier(module.name)
// the special name is required for `KlibMetadataModuleDescriptorFactoryImpl.createDescriptorOptionalBuiltIns`
// it doesn't seem convincingly legitimate, probably should be refactored
val moduleName = Name.special("<${module.name}>")
val languageVersionSettings = module.languageVersionSettings
val analyzerServices = module.targetPlatform.getAnalyzerServices()
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
@@ -249,7 +251,7 @@ private fun getJsDependencies(module: TestModule, testServices: TestServices): T
return Triple(runtimeKlibsPaths, transitiveLibraries, friendLibraries)
}
internal fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List<String> {
fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List<String> {
val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices)
return runtimeKlibsPaths + transitiveLibraries.map { it.path } + friendLibraries.map { it.path }
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
import org.jetbrains.kotlin.js.config.*
@@ -155,7 +156,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
ConfigurationDirectives.WITH_STDLIB in module.directives
val names = if (needsFullIrRuntime) listOf("full.stdlib", "kotlin.test") else listOf("reduced.stdlib")
names.mapNotNullTo(result) { System.getProperty("kotlin.js.$it.path") }
names.mapNotNullTo(result) { System.getProperty("kotlin.js.$it.path")?.let { File(it).absolutePath } }
val runtimeClasspaths = testServices.runtimeClasspathProviders.flatMap { it.runtimeClassPaths(module) }
runtimeClasspaths.mapTo(result) { it.absolutePath }
return result
@@ -176,7 +177,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
return visited.map { testServices.dependencyProvider.getArtifact(it, ArtifactKinds.KLib).outputFile }
}
fun getDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List<ModuleDescriptorImpl> {
fun getDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List<ModuleDescriptor> {
return getKlibDependencies(module, testServices, kind)
.map { testServices.jsLibraryProvider.getDescriptorByPath(it.absolutePath) }
}
@@ -190,7 +191,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
fun getAllRecursiveDependenciesFor(module: TestModule, testServices: TestServices): Set<ModuleDescriptorImpl> {
val visited = mutableSetOf<ModuleDescriptorImpl>()
fun getRecursive(descriptor: ModuleDescriptorImpl) {
fun getRecursive(descriptor: ModuleDescriptor) {
descriptor.allDependencyModules.forEach {
if (it is ModuleDescriptorImpl && it !in visited) {
visited += it
@@ -29,7 +29,7 @@ object ReflectionBasedTargetBackendComputer : TargetBackendComputer {
}
require(testKClass.isOpen) {
"""
Test runner which inherits from ${runnerMarkerKClass.simpleName} and used as base class
Test runner ${testKClass.simpleName} which inherits from ${runnerMarkerKClass.simpleName} and used as base class
for real test should have `open` modality
""".trimIndent()
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ContextForNewModule
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.js.di.createContainerForJS
@@ -44,6 +45,7 @@ import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.serialization.js.PackagesWithHeaderMetadata
import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
abstract class AbstractTopDownAnalyzerFacadeForJS {
@@ -51,11 +53,11 @@ abstract class AbstractTopDownAnalyzerFacadeForJS {
files: Collection<KtFile>,
project: Project,
configuration: CompilerConfiguration,
moduleDescriptors: List<ModuleDescriptorImpl>,
friendModuleDescriptors: List<ModuleDescriptorImpl>,
moduleDescriptors: List<ModuleDescriptor>,
friendModuleDescriptors: List<ModuleDescriptor>,
targetEnvironment: TargetEnvironment,
thisIsBuiltInsModule: Boolean = false,
customBuiltInsModule: ModuleDescriptorImpl? = null
customBuiltInsModule: ModuleDescriptor? = null
): JsAnalysisResult {
require(!thisIsBuiltInsModule || customBuiltInsModule == null) {
"Can't simultaneously use custom built-ins module and set current module as built-ins"
@@ -83,7 +85,8 @@ abstract class AbstractTopDownAnalyzerFacadeForJS {
}
val dependencies = mutableSetOf(context.module) + moduleDescriptors + builtIns.builtInsModule
context.module.setDependencies(dependencies.toList(), friendModuleDescriptors.toSet())
@Suppress("UNCHECKED_CAST")
context.module.setDependencies(dependencies.toList() as List<ModuleDescriptorImpl>, friendModuleDescriptors.toSet() as Set<ModuleDescriptorImpl>)
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
@@ -10,14 +10,12 @@ import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.classicFrontendHandlersStep
import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.builders.jsArtifactsHandlersStep
import org.jetbrains.kotlin.test.builders.*
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.DIAGNOSTICS
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticsHandler
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.runners.codegen.commonClassicFrontendHandlersForCodegenTest
@@ -105,6 +103,10 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
useHandlers(::ClassicDiagnosticsHandler)
}
firHandlersStep {
useHandlers(::FirDiagnosticsHandler)
}
facadeStep(frontendToBackendConverter)
irHandlersStep()
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2021 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.js.test.converters
import org.jetbrains.kotlin.config.CommonConfigurationKeys
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.util.IrMessageLogger
import org.jetbrains.kotlin.js.test.utils.JsIrIncrementalDataProvider
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.test.backend.ir.IrBackendFacade
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.frontend.classic.ModuleDescriptorProvider
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
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.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.io.File
class FirJsKlibBackendFacade(
testServices: TestServices,
private val firstTimeCompilation: Boolean
) : IrBackendFacade<BinaryArtifacts.KLib>(testServices, ArtifactKinds.KLib) {
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::JsIrIncrementalDataProvider), service(::ModuleDescriptorProvider))
constructor(testServices: TestServices): this(testServices, firstTimeCompilation = true)
override fun shouldRunAnalysis(module: TestModule): Boolean {
return module.backendKind == inputKind
}
override fun transform(module: TestModule, inputArtifact: IrBackendInput): BinaryArtifacts.KLib {
require(inputArtifact is IrBackendInput.JsIrBackendInput) {
"JsKlibBackendFacade expects IrBackendInput.JsIrBackendInput as input"
}
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val outputFile = JsEnvironmentConfigurator.getJsKlibArtifactPath(testServices, module.name)
// TODO: consider avoiding repeated libraries resolution
val libraries = resolveJsLibraries(module, testServices, configuration)
if (firstTimeCompilation) {
serializeModuleIntoKlib(
configuration[CommonConfigurationKeys.MODULE_NAME]!!,
configuration,
configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None,
inputArtifact.sourceFiles,
klibPath = outputFile,
libraries.map { it.library },
inputArtifact.irModuleFragment,
inputArtifact.expectDescriptorToSymbol,
cleanFiles = inputArtifact.icData,
nopack = true,
perFile = false,
containsErrorCode = inputArtifact.hasErrors,
abiVersion = KotlinAbiVersion.CURRENT, // TODO get from test file data
jsOutputName = null,
inputArtifact.serializeSingleFile
)
}
// TODO: consider avoiding repeated libraries resolution
val lib = jsResolveLibraries(
getAllJsDependenciesPaths(module, testServices) + listOf(outputFile),
emptyList(),
configuration.resolverLogger
).getFullResolvedList().last().library
val moduleDescriptor = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
lib,
configuration.languageVersionSettings,
LockBasedStorageManager("ModulesStructure"),
inputArtifact.irModuleFragment.descriptor.builtIns,
packageAccessHandler = null,
lookupTracker = LookupTracker.DO_NOTHING
)
// TODO: find out why it must be so weird
moduleDescriptor.safeAs<ModuleDescriptorImpl>()?.let {
it.setDependencies(inputArtifact.irModuleFragment.descriptor.allDependencyModules.filterIsInstance<ModuleDescriptorImpl>() + it)
}
testServices.moduleDescriptorProvider.replaceModuleDescriptorForModule(module, moduleDescriptor)
if (JsEnvironmentConfigurator.incrementalEnabled(testServices)) {
testServices.jsIrIncrementalDataProvider.recordIncrementalData(module, lib)
}
testServices.jsLibraryProvider.setDescriptorAndLibraryByName(outputFile, moduleDescriptor, lib)
return BinaryArtifacts.KLib(File(outputFile))
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.js.test.ir
import org.jetbrains.kotlin.js.test.AbstractJsBlackBoxCodegenTestBase
import org.jetbrains.kotlin.js.test.converters.FirJsKlibBackendFacade
import org.jetbrains.kotlin.js.test.JsSteppingTestAdditionalSourceProvider
import org.jetbrains.kotlin.js.test.converters.JsIrBackendFacade
import org.jetbrains.kotlin.js.test.converters.JsKlibBackendFacade
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.test.directives.*
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2IrConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrJsResultsConverter
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
@@ -186,7 +188,7 @@ private class SkipMultiModuleTestsMetaConfigurator(testServices: TestServices) :
}
}
abstract class AbstractFirJsTest(
open class AbstractFirJsTest(
pathToTestDir: String = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/box/",
testGroupOutputDirPrefix: String = "box/",
) : AbstractJsBlackBoxCodegenTestBase<FirOutputArtifact, IrBackendInput, BinaryArtifacts.KLib>(
@@ -196,10 +198,10 @@ abstract class AbstractFirJsTest(
get() = ::FirFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<FirOutputArtifact, IrBackendInput>>
get() = ::Fir2IrResultsConverter
get() = ::Fir2IrJsResultsConverter
override val backendFacade: Constructor<BackendFacade<IrBackendInput, BinaryArtifacts.KLib>>
get() = ::JsKlibBackendFacade
get() = ::FirJsKlibBackendFacade
override val afterBackendFacade: Constructor<AbstractTestFacade<BinaryArtifacts.KLib, BinaryArtifacts.Js>>?
get() = ::JsIrBackendFacade
@@ -213,8 +215,6 @@ abstract class AbstractFirJsTest(
super.configure(builder)
with (builder) {
defaultDirectives {
+ConfigurationDirectives.WITH_STDLIB
+LanguageSettingsDirectives.ALLOW_KOTLIN_PACKAGE
val runIc = getBoolean("kotlin.js.ir.icMode")
if (runIc) +JsEnvironmentConfigurationDirectives.RUN_IC
if (getBoolean("kotlin.js.ir.klibMainModule")) +JsEnvironmentConfigurationDirectives.KLIB_MAIN_MODULE
@@ -1,6 +1,6 @@
// IGNORE_FIR
// EXPECTED_REACHABLE_NODES: 1253
// MODULE: lib
// NO_COMMON_FILES
// FILE: lib.kt
interface II {
companion object : DDD by error("OK")
@@ -11,6 +11,7 @@ interface DDD {
}
// MODULE: main(lib)
// NO_COMMON_FILES
// FILE: main.kt
fun box() : String {
try {