diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt index 733f0a6e0ad..ec1f891a1d2 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt @@ -50,7 +50,7 @@ class KlibBasedSymbolProvider( } override fun computePackagePartsInfos(packageFqName: FqName): List { - val packageStringName = packageFqName.asString() + val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString() if (packageStringName !in fragmentNameList) { return emptyList() diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt index 117b339ab89..cd85289059c 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt @@ -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) { } diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/firKlibSerialization.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/firKlibSerialization.kt index 3f45cb34225..69f6520e4ee 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/firKlibSerialization.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/firKlibSerialization.kt @@ -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().sortedBy { it.classId.asFqNameString() } + fun List.makeClassesProtoWithNested(): List> = + // TODO: filter out expects + filterIsInstance().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()) +} diff --git a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/services/JsLibraryProvider.kt b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/services/JsLibraryProvider.kt index 82b88d735c0..16377c457d1 100644 --- a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/services/JsLibraryProvider.kt +++ b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/services/JsLibraryProvider.kt @@ -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() - private val stdlibPathToDescriptor = mutableMapOf() + private val stdlibPathToDescriptor = mutableMapOf() - 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 { + fun getOrCreateStdlibByPath(path: String, create: (String) -> Pair): ModuleDescriptor { return stdlibPathToDescriptor.getOrPut(path) { create(path).let { descriptorToLibrary += it diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrInterpreterDumpHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrInterpreterDumpHandler.kt index 002af2fa17b..25b00ff4618 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrInterpreterDumpHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrInterpreterDumpHandler.kt @@ -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? { + private fun getDump(module: TestModule): Pair? { 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() diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt index ceecf0ab255..00d7e268b85 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt @@ -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, + friendsDescriptors = multiplatformAnalysisConfiguration.getFriendDescriptors(module) as List, + dependsOnDescriptors = multiplatformAnalysisConfiguration.getDependsOnDescriptors(module) as List ) moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor) return ClassicFrontendOutputArtifact( @@ -251,7 +253,7 @@ class ClassicFrontendFacade( ) } - private fun loadKlib(names: List, configuration: CompilerConfiguration): List { + private fun loadKlib(names: List, configuration: CompilerConfiguration): List { val resolvedLibraries = jsResolveLibraries( names, configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(), @@ -261,8 +263,8 @@ class ClassicFrontendFacade( var builtInsModule: KotlinBuiltIns? = null val dependencies = mutableListOf() - 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, - dependencyDescriptors: List, - friendsDescriptors: List, + dependencyDescriptors: List, + friendsDescriptors: List, ): AnalysisResult { val runtimeKlibsNames = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices) val runtimeKlibs = loadKlib(runtimeKlibsNames, configuration) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ModuleDescriptorProvider.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ModuleDescriptorProvider.kt index 57717a45165..6f906f05815 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ModuleDescriptorProvider.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ModuleDescriptorProvider.kt @@ -15,16 +15,15 @@ import org.jetbrains.kotlin.test.model.TestModule class ModuleDescriptorProvider( private val testServices: TestServices ) : TestService { - private val moduleDescriptorByModule = mutableMapOf() + private val moduleDescriptorByModule = mutableMapOf() - 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 } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/MultiplatformAnalysisConfiguration.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/MultiplatformAnalysisConfiguration.kt index 322428a24a9..ad80873006d 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/MultiplatformAnalysisConfiguration.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/MultiplatformAnalysisConfiguration.kt @@ -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 - fun getDependencyDescriptors(module: TestModule): List - fun getFriendDescriptors(module: TestModule): List - fun getDependsOnDescriptors(module: TestModule): List + fun getDependencyDescriptors(module: TestModule): List + fun getFriendDescriptors(module: TestModule): List + fun getDependsOnDescriptors(module: TestModule): List } /** @@ -63,18 +63,18 @@ internal class MultiplatformSeparateAnalysisConfiguration( return CompilerEnvironment } - override fun getDependencyDescriptors(module: TestModule): List { + override fun getDependencyDescriptors(module: TestModule): List { return getDescriptors( module.allDependencies - module.dependsOnDependencies.toSet(), dependencyProvider, moduleDescriptorProvider ) } - override fun getDependsOnDescriptors(module: TestModule): List { + override fun getDependsOnDescriptors(module: TestModule): List { return emptyList() } - override fun getFriendDescriptors(module: TestModule): List { + override fun getFriendDescriptors(module: TestModule): List { 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 { + override fun getDependencyDescriptors(module: TestModule): List { // 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 { + override fun getDependsOnDescriptors(module: TestModule): List { return getDescriptors(module.dependsOnDependencies, dependencyProvider, moduleDescriptorProvider) } - override fun getFriendDescriptors(module: TestModule): List { + override fun getFriendDescriptors(module: TestModule): List { return getDescriptors(module.friendDependencies, dependencyProvider, moduleDescriptorProvider) } } @@ -177,7 +177,7 @@ private fun getDescriptors( dependencies: Iterable, dependencyProvider: DependencyProvider, moduleDescriptorProvider: ModuleDescriptorProvider -): List { +): List { return dependencies.filter { it.kind == DependencyKind.Source } .map { dependencyDescription -> dependencyProvider.getTestModule(dependencyDescription.moduleName) } .map { dependencyModule -> moduleDescriptorProvider.getModuleDescriptor(dependencyModule) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt new file mode 100644 index 00000000000..410569a53c7 --- /dev/null +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt @@ -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( + 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() + 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, + 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, + languageVersionSettings: LanguageVersionSettings, + testServices: TestServices +): Pair, KotlinBuiltIns?> { + var builtInsModule: KotlinBuiltIns? = null + val dependencies = mutableListOf() + + 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 +} diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt index dc9f340c9e6..42285d505e6 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt @@ -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 { +fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List { val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices) return runtimeKlibsPaths + transitiveLibraries.map { it.path } + friendLibraries.map { it.path } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt index ae78d944c53..5e4282a0729 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt @@ -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 { + fun getDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List { 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 { val visited = mutableSetOf() - fun getRecursive(descriptor: ModuleDescriptorImpl) { + fun getRecursive(descriptor: ModuleDescriptor) { descriptor.allDependencyModules.forEach { if (it is ModuleDescriptorImpl && it !in visited) { visited += it diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/ReflectionBasedTargetBackendComputer.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/ReflectionBasedTargetBackendComputer.kt index 63398a94c73..0938139553e 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/ReflectionBasedTargetBackendComputer.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/ReflectionBasedTargetBackendComputer.kt @@ -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() } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.kt index 08b0ad23d85..35205de0225 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/analyze/TopDownAnalyzerFacadeForJS.kt @@ -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, project: Project, configuration: CompilerConfiguration, - moduleDescriptors: List, - friendModuleDescriptors: List, + moduleDescriptors: List, + friendModuleDescriptors: List, 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, friendModuleDescriptors.toSet() as Set) val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsBlackBoxCodegenTestBase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsBlackBoxCodegenTestBase.kt index 318fc16763c..e931eaa2bde 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsBlackBoxCodegenTestBase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsBlackBoxCodegenTestBase.kt @@ -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(testServices, ArtifactKinds.KLib) { + + override val additionalServices: List + 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()?.let { + it.setDependencies(inputArtifact.irModuleFragment.descriptor.allDependencyModules.filterIsInstance() + 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)) + } +} \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsIrTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsIrTest.kt index fd1e85e06f0..8a1834ab97c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsIrTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsIrTest.kt @@ -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( @@ -196,10 +198,10 @@ abstract class AbstractFirJsTest( get() = ::FirFrontendFacade override val frontendToBackendConverter: Constructor> - get() = ::Fir2IrResultsConverter + get() = ::Fir2IrJsResultsConverter override val backendFacade: Constructor> - get() = ::JsKlibBackendFacade + get() = ::FirJsKlibBackendFacade override val afterBackendFacade: Constructor>? 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 diff --git a/js/js.translator/testData/box/delegation/delegationByCompanionToNothing.kt b/js/js.translator/testData/box/delegation/delegationByCompanionToNothing.kt index bd7258fc10d..8e98231823f 100644 --- a/js/js.translator/testData/box/delegation/delegationByCompanionToNothing.kt +++ b/js/js.translator/testData/box/delegation/delegationByCompanionToNothing.kt @@ -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 {