From 9a9beef25b3c2c0856fe073b2b8beff3f02558ac Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Fri, 24 Dec 2021 12:16:57 +0300 Subject: [PATCH] [FIR JS] Prepare the infrastructure for FIR JS tests --- .../KlibBasedAnnotationDeserializer.kt | 27 ++ .../fir/session/KlibBasedSymbolProvider.kt | 134 ++++++++ .../AbstractAnnotationDeserializer.kt | 4 +- .../test/frontend/fir/FirFrontendFacade.kt | 303 ++++++++++++++++-- .../test/frontend/fir/FirJsSessionFactory.kt | 143 +++++++++ .../fir/FirJsSyntheticNamesProvider.kt | 18 ++ .../fir/JsConeConflictResolverFactory.kt | 34 ++ .../JsEnvironmentConfigurator.kt | 11 +- .../js/analyze/TopDownAnalyzerFacadeForJS.kt | 3 + .../js/resolve/JsTypeSpecificityComparator.kt | 7 +- 10 files changed, 644 insertions(+), 40 deletions(-) create mode 100644 compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedAnnotationDeserializer.kt create mode 100644 compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt create mode 100644 compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSessionFactory.kt create mode 100644 compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSyntheticNamesProvider.kt create mode 100644 compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/JsConeConflictResolverFactory.kt diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedAnnotationDeserializer.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedAnnotationDeserializer.kt new file mode 100644 index 00000000000..70cda454bce --- /dev/null +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedAnnotationDeserializer.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2022 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.fir.session + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.deserialization.AbstractAnnotationDeserializer +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf +import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.NameResolver +import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol + +class KlibBasedAnnotationDeserializer( + session: FirSession +) : AbstractAnnotationDeserializer(session) { + override val protocol: SerializerExtensionProtocol + get() = KlibMetadataSerializerProtocol + + override fun loadTypeAnnotations(typeProto: ProtoBuf.Type, nameResolver: NameResolver): List { + val annotations = typeProto.getExtension(KlibMetadataProtoBuf.typeAnnotation).orEmpty() + return annotations.map { deserializeAnnotation(it, nameResolver) } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..733f0a6e0ad --- /dev/null +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt @@ -0,0 +1,134 @@ +/* + * 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.fir.session + +import org.jetbrains.kotlin.descriptors.SourceFile +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.deserialization.* +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider +import org.jetbrains.kotlin.library.metadata.KlibMetadataClassDataFinder +import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration +import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource +import java.nio.file.Paths + +class KlibBasedSymbolProvider( + session: FirSession, + moduleDataProvider: ModuleDataProvider, + kotlinScopeProvider: FirKotlinScopeProvider, + private val resolvedLibrary: KotlinResolvedLibrary, + defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library +) : AbstractFirDeserializedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, defaultDeserializationOrigin) { + private val moduleHeader by lazy { + resolvedLibrary.loadModuleHeader(resolvedLibrary.library) + } + + private val fragmentNameList by lazy { + moduleHeader.packageFragmentNameList.toSet() + } + + private val annotationDeserializer = KlibBasedAnnotationDeserializer(session) + private val constDeserializer = FirConstDeserializer(session) + private val deserializationConfiguration = CompilerDeserializationConfiguration(session.languageVersionSettings) + private val cachedFragments = mutableMapOf, ProtoBuf.PackageFragment>() + + private fun getPackageFragment(packageStringName: String, packageMetadataPart: String): ProtoBuf.PackageFragment { + return cachedFragments.getOrPut(packageStringName to packageMetadataPart) { + resolvedLibrary.loadPackageFragment(resolvedLibrary.library, packageStringName, packageMetadataPart) + } + } + + override fun computePackagePartsInfos(packageFqName: FqName): List { + val packageStringName = packageFqName.asString() + + if (packageStringName !in fragmentNameList) { + return emptyList() + } + + return resolvedLibrary.library.packageMetadataParts(packageStringName).mapNotNull { + val fragment = getPackageFragment(packageStringName, it) + + val libraryPath = Paths.get(resolvedLibrary.library.libraryName) + val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return@mapNotNull null + val packageProto = fragment.`package` + + val nameResolver = NameResolverImpl( + fragment.strings, + fragment.qualifiedNames, + ) + + PackagePartsCacheData( + packageProto, + FirDeserializationContext.createForPackage( + packageFqName, packageProto, nameResolver, moduleData, + annotationDeserializer, + constDeserializer, + null, + ), + ) + } + } + + override fun extractClassMetadata(classId: ClassId, parentContext: FirDeserializationContext?): ClassMetadataFindResult? { + val packageStringName = classId.packageFqName.asString() + + if (packageStringName !in fragmentNameList) { + return null + } + + resolvedLibrary.library.packageMetadataParts(packageStringName).forEach { + val libraryPath = Paths.get(resolvedLibrary.library.libraryName) + val fragment = getPackageFragment(packageStringName, it) + + val nameResolver = NameResolverImpl( + fragment.strings, + fragment.qualifiedNames, + ) + + val finder = KlibMetadataClassDataFinder(fragment, nameResolver) + val classProto = finder.findClassData(classId)?.classProto ?: return@forEach + + val source = object : DeserializedContainerSource { + override val incompatibility: IncompatibleVersionErrorData<*>? = null + override val isPreReleaseInvisible = + deserializationConfiguration.reportErrorsOnPreReleaseDependencies && (moduleHeader.flags and 1) != 0 + override val abiStability = DeserializedContainerAbiStability.STABLE + override val presentableString = "Package '${classId.packageFqName}'" + + override fun getContainingFile() = SourceFile.NO_SOURCE_FILE + } + + return ClassMetadataFindResult.Metadata( + nameResolver, + classProto, + annotationDeserializer, + moduleDataProvider.getModuleData(libraryPath), + source, + classPostProcessor = {} + ) + } + + return null + } + + override fun isNewPlaceForBodyGeneration(classProto: ProtoBuf.Class) = false + + override fun getPackage(fqName: FqName): FqName? { + return if (fqName.toString() in fragmentNameList) { + fqName + } else { + null + } + } +} diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt index badad9af1de..6122485b6c4 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.protobuf.MessageLite +import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.getClassId @@ -44,7 +45,8 @@ import org.jetbrains.kotlin.types.ConstantValueKind abstract class AbstractAnnotationDeserializer( private val session: FirSession ) { - protected val protocol = BuiltInSerializerProtocol + protected open val protocol: SerializerExtensionProtocol + get() = BuiltInSerializerProtocol open fun inheritAnnotationInfo(parent: AbstractAnnotationDeserializer) { } 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 2029d3c9a87..09039ce2518 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 @@ -5,9 +5,11 @@ package org.jetbrains.kotlin.test.frontend.fir +import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiElementFinder +import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.ProjectScope import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices import org.jetbrains.kotlin.asJava.finder.JavaElementFinder @@ -17,13 +19,22 @@ import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.compiler.VfsBasedProjectEnvironment import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots +import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.FirAnalyzerFacade import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar -import org.jetbrains.kotlin.fir.moduleData +import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.session.FirSessionFactory +import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries +import org.jetbrains.kotlin.ir.backend.js.toResolverLogger +import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices +import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.isCommon @@ -36,10 +47,14 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.model.DirectivesContainer +import org.jetbrains.kotlin.test.model.DependencyRelation import org.jetbrains.kotlin.test.model.FrontendFacade 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 +import java.io.File +import java.nio.file.Paths class FirFrontendFacade( testServices: TestServices, @@ -72,48 +87,51 @@ class FirFrontendFacade( testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList() } + val moduleName = Name.identifier(module.name) val languageVersionSettings = module.languageVersionSettings - val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module) - + val analyzerServices = module.targetPlatform.getAnalyzerServices() val configuration = compilerConfigurationProvider.getCompilerConfiguration(module) + val extensionRegistrars = FirExtensionRegistrar.getInstances(project) - val librariesScope = ProjectScope.getLibrariesScope(project) - val sourcesScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles) - - val session = FirSessionFactory.createSessionWithDependencies( - Name.identifier(module.name), - module.targetPlatform, - module.targetPlatform.getAnalyzerServices(), - moduleInfoProvider.firSessionProvider, - VfsBasedProjectEnvironment( - project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL), - { packagePartProviderFactory.invoke(it) } - ), - languageVersionSettings, - PsiBasedProjectFileSearchScope(sourcesScope), - PsiBasedProjectFileSearchScope(librariesScope), - lookupTracker = null, - enumWhenTracker = null, - incrementalCompilationContext = null, - extensionRegistrars = FirExtensionRegistrar.getInstances(project), - needRegisterJavaElementFinder = true, - dependenciesConfigurator = { - dependencies(configuration.jvmModularRoots.map { it.toPath() }) - dependencies(configuration.jvmClasspathRoots.map { it.toPath() }) - - friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList()) - - sourceDependencies(moduleInfoProvider.getRegularDependentSourceModules(module)) - sourceFriendsDependencies(moduleInfoProvider.getDependentFriendSourceModules(module)) - sourceDependsOnDependencies(moduleInfoProvider.getDependentDependsOnSourceModules(module)) - } - ) { + val sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = { if (FirDiagnosticsDirectives.WITH_EXTENDED_CHECKERS in module.directives) { registerExtendedCommonCheckers() } additionalSessionConfiguration?.invoke(this) } + val session = when { + module.targetPlatform.isJvm() || module.targetPlatform.isCommon() -> { + configureSessionsForJvmOrCommon( + module, + moduleName, + project, + ktFiles, + compilerConfigurationProvider, + moduleInfoProvider, + analyzerServices, + configuration, + sessionConfigurator, + extensionRegistrars, + languageVersionSettings, + ) + } + module.targetPlatform.isJs() -> { + configureSessionsForJs( + module, + moduleName, + moduleInfoProvider, + analyzerServices, + configuration, + testServices, + sessionConfigurator, + extensionRegistrars, + languageVersionSettings, + ) + } + else -> error("Unsupported") + } + moduleInfoProvider.registerModuleData(module, session.moduleData) val enablePluginPhases = FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES in module.directives @@ -136,6 +154,223 @@ class FirFrontendFacade( } } +private fun DependencyListForCliModule.Builder.configureJvmDependencies( + configuration: CompilerConfiguration, +) { + dependencies(configuration.jvmModularRoots.map { it.toPath() }) + dependencies(configuration.jvmClasspathRoots.map { it.toPath() }) + + friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList()) +} + +private fun DependencyListForCliModule.Builder.configureJsDependencies( + module: TestModule, + testServices: TestServices, +) { + val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices) + + dependencies(runtimeKlibsPaths.map { Paths.get(it).toAbsolutePath() }) + dependencies(transitiveLibraries.map { it.toPath().toAbsolutePath() }) + + friendDependencies(friendLibraries.map { it.toPath().toAbsolutePath() }) +} + +private fun getJsDependencies(module: TestModule, testServices: TestServices): Triple, List, List> { + val runtimeKlibsPaths = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices) + val transitiveLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.RegularDependency) + val friendLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.FriendDependency) + return Triple(runtimeKlibsPaths, transitiveLibraries, friendLibraries) +} + +private fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List { + val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices) + return runtimeKlibsPaths + transitiveLibraries.map { it.path } + friendLibraries.map { it.path } +} + +fun resolveJsLibraries( + module: TestModule, + testServices: TestServices, + configuration: CompilerConfiguration +): List { + val paths = getAllJsDependenciesPaths(module, testServices) + val repositories = configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList() + val logger = configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + return jsResolveLibraries(paths, repositories, logger).getFullResolvedList() +} + +private fun buildDependencyList( + module: TestModule, + moduleName: Name, + moduleInfoProvider: FirModuleInfoProvider, + analyzerServices: PlatformDependentAnalyzerServices, + configureDependencies: DependencyListForCliModule.Builder.() -> Unit, +) = DependencyListForCliModule.build(moduleName, module.targetPlatform, analyzerServices) { + configureDependencies() + sourceDependencies(moduleInfoProvider.getRegularDependentSourceModules(module)) + sourceFriendsDependencies(moduleInfoProvider.getDependentFriendSourceModules(module)) + sourceDependsOnDependencies(moduleInfoProvider.getDependentDependsOnSourceModules(module)) +} + +private fun configureSessionsForJvmOrCommon( + module: TestModule, + moduleName: Name, + project: Project, + ktFiles: Collection, + compilerConfigurationProvider: CompilerConfigurationProvider, + moduleInfoProvider: FirModuleInfoProvider, + analyzerServices: PlatformDependentAnalyzerServices, + configuration: CompilerConfiguration, + sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit, + extensionRegistrars: List, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, +): FirSession { + val librariesScope = ProjectScope.getLibrariesScope(project) + val sourcesScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles) + + val dependencyList = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) { + configureJvmDependencies(configuration) + } + + configureLibrarySessionForJvmOrCommon( + module, + moduleName, + moduleInfoProvider.firSessionProvider, + dependencyList, + librariesScope, + project, + compilerConfigurationProvider, + languageVersionSettings, + ) + + val mainModuleData = FirModuleDataImpl( + moduleName, + dependencyList.regularDependencies, + dependencyList.dependsOnDependencies, + dependencyList.friendsDependencies, + dependencyList.platform, + dependencyList.analyzerServices + ) + + return configureMainSessionForJvmOrCommon( + module, + project, + compilerConfigurationProvider, + sessionConfigurator, + extensionRegistrars, + sourcesScope, + mainModuleData, + moduleInfoProvider.firSessionProvider, + languageVersionSettings, + ) +} + +private fun configureLibrarySessionForJvmOrCommon( + module: TestModule, + moduleName: Name, + sessionProvider: FirProjectSessionProvider, + dependencyList: DependencyListForCliModule, + librariesScope: GlobalSearchScope, + project: Project, + compilerConfigurationProvider: CompilerConfigurationProvider, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, +): FirSession { + val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module) + + val projectEnvironment = VfsBasedProjectEnvironment( + project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL), + ) { packagePartProviderFactory.invoke(it) } + + val projectFileSearchScope = PsiBasedProjectFileSearchScope(librariesScope) + + return FirSessionFactory.createLibrarySession( + moduleName, + sessionProvider, + dependencyList.moduleDataProvider, + projectFileSearchScope, + projectEnvironment, + projectEnvironment.getPackagePartProvider(projectFileSearchScope), + languageVersionSettings, + ) +} + +private fun configureMainSessionForJvmOrCommon( + module: TestModule, + project: Project, + compilerConfigurationProvider: CompilerConfigurationProvider, + sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit, + extensionRegistrars: List, + sourcesScope: GlobalSearchScope, + mainModuleData: FirModuleData, + sessionProvider: FirProjectSessionProvider, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, +): FirSession { + val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module) + + val projectEnvironment = VfsBasedProjectEnvironment( + project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL), + ) { packagePartProviderFactory.invoke(it) } + + val projectFileSearchScope = PsiBasedProjectFileSearchScope(sourcesScope) + + return FirSessionFactory.createJavaModuleBasedSession( + mainModuleData, + sessionProvider, + projectFileSearchScope, + projectEnvironment, + incrementalCompilationContext = null, + extensionRegistrars, + languageVersionSettings, + lookupTracker = null, + enumWhenTracker = null, + needRegisterJavaElementFinder = true, + sessionConfigurator, + ) +} + +private fun configureSessionsForJs( + module: TestModule, + moduleName: Name, + moduleInfoProvider: FirModuleInfoProvider, + analyzerServices: PlatformDependentAnalyzerServices, + configuration: CompilerConfiguration, + testServices: TestServices, + sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit, + extensionRegistrars: List, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, +): FirSession { + val dependencyList = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) { + configureJsDependencies(module, testServices) + } + + FirJsSessionFactory.createJsLibrarySession( + moduleName, + module, + testServices, + configuration, + moduleInfoProvider.firSessionProvider, + dependencyList.moduleDataProvider, + languageVersionSettings, + ) + + val mainModuleData = FirModuleDataImpl( + moduleName, + dependencyList.regularDependencies, + dependencyList.dependsOnDependencies, + dependencyList.friendsDependencies, + dependencyList.platform, + dependencyList.analyzerServices + ) + + return FirJsSessionFactory.createJsModuleBasedSession( + mainModuleData, + moduleInfoProvider.firSessionProvider, + extensionRegistrars, + languageVersionSettings, + null, + sessionConfigurator, + ) +} + fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices { return when { isJvm() -> JvmPlatformAnalyzerServices diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSessionFactory.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSessionFactory.kt new file mode 100644 index 00000000000..3ae780d2bc0 --- /dev/null +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSessionFactory.kt @@ -0,0 +1,143 @@ +/* + * 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.test.frontend.fir + +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper +import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers +import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider +import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar +import org.jetbrains.kotlin.fir.extensions.FirSwitchableExtensionDeclarationsSymbolProvider +import org.jetbrains.kotlin.fir.java.FirCliSession +import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider +import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory +import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.impl.* +import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped +import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider +import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper +import org.jetbrains.kotlin.fir.session.* +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices + +object FirJsSessionFactory { + @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) + fun createJsLibrarySession( + mainModuleName: Name, + module: TestModule, + testServices: TestServices, + configuration: CompilerConfiguration, + sessionProvider: FirProjectSessionProvider, + moduleDataProvider: ModuleDataProvider, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, + ): FirSession { + return FirCliSession(sessionProvider, FirSession.Kind.Library).apply session@{ + moduleDataProvider.allModuleData.forEach { + sessionProvider.registerSession(it, this) + it.bindSession(this) + } + + registerCliCompilerOnlyComponents() + registerCommonComponents(languageVersionSettings) + + val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) + register(FirKotlinScopeProvider::class, kotlinScopeProvider) + + val builtinsModuleData = FirSessionFactory.createModuleDataForBuiltins( + mainModuleName, + moduleDataProvider.platform, + moduleDataProvider.analyzerServices + ).also { it.bindSession(this@session) } + + val klibProviders = resolveJsLibraries(module, testServices, configuration).map { + KlibBasedSymbolProvider(this@session, moduleDataProvider, kotlinScopeProvider, it) + } + + val otherProviders = listOf( + FirBuiltinSymbolProvider(this, builtinsModuleData, kotlinScopeProvider), + FirCloneableSymbolProvider(this, builtinsModuleData, kotlinScopeProvider), + FirDependenciesSymbolProviderImpl(this) + ) + + val symbolProvider = FirCompositeSymbolProvider(this, otherProviders + klibProviders) + + register(FirSymbolProvider::class, symbolProvider) + register(FirProvider::class, FirLibrarySessionProvider(symbolProvider)) + } + } + + @OptIn(SessionConfiguration::class) + fun FirSession.registerJsSpecificResolveComponents() { + register(FirVisibilityChecker::class, FirVisibilityChecker.Default) + register(ConeCallConflictResolverFactory::class, JsCallConflictResolverFactory) + register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default) + register(FirSyntheticNamesProvider::class, FirJsSyntheticNamesProvider) + register(FirOverridesBackwardCompatibilityHelper::class, FirOverridesBackwardCompatibilityHelper.Default()) + } + + @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) + fun createJsModuleBasedSession( + moduleData: FirModuleData, + sessionProvider: FirProjectSessionProvider, + extensionRegistrars: List, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, + lookupTracker: LookupTracker? = null, + init: FirSessionFactory.FirSessionConfigurator.() -> Unit = {} + ): FirSession { + return FirCliSession(sessionProvider, FirSession.Kind.Source).apply session@{ + moduleData.bindSession(this@session) + sessionProvider.registerSession(moduleData, this@session) + registerModuleData(moduleData) + registerCliCompilerOnlyComponents() + registerCommonComponents(languageVersionSettings) + registerResolveComponents(lookupTracker) + registerJsSpecificResolveComponents() + + val kotlinScopeProvider = FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } + register(FirKotlinScopeProvider::class, kotlinScopeProvider) + + val firProvider = FirProviderImpl(this, kotlinScopeProvider) + register(FirProvider::class, firProvider) + + FirSessionFactory.FirSessionConfigurator(this).apply { + registerCommonCheckers() + for (extensionRegistrar in extensionRegistrars) { + registerExtensions(extensionRegistrar.configure()) + } + init() + }.configure() + + val dependenciesSymbolProvider = FirDependenciesSymbolProviderImpl(this) + val generatedSymbolsProvider = FirSwitchableExtensionDeclarationsSymbolProvider.create(this) + register( + FirSymbolProvider::class, + FirCompositeSymbolProvider( + this, + listOfNotNull( + firProvider.symbolProvider, + generatedSymbolsProvider, + dependenciesSymbolProvider, + ) + ) + ) + + generatedSymbolsProvider?.let { register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it) } + + register( + FirDependenciesSymbolProvider::class, + dependenciesSymbolProvider + ) + } + } +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSyntheticNamesProvider.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSyntheticNamesProvider.kt new file mode 100644 index 00000000000..c5b8509abcb --- /dev/null +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirJsSyntheticNamesProvider.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2022 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.fir.NoMutableState +import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider +import org.jetbrains.kotlin.load.java.setMethodName +import org.jetbrains.kotlin.name.Name + +@NoMutableState +object FirJsSyntheticNamesProvider : FirSyntheticNamesProvider() { + override fun possibleGetterNamesByPropertyName(name: Name): List = emptyList() + override fun setterNameByGetterName(name: Name): Name = setMethodName(getMethodName = name) + override fun possiblePropertyNamesByAccessorName(name: Name): List = emptyList() +} diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/JsConeConflictResolverFactory.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/JsConeConflictResolverFactory.kt new file mode 100644 index 00000000000..c6632c4c031 --- /dev/null +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/JsConeConflictResolverFactory.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2022 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.fir.NoMutableState +import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory +import org.jetbrains.kotlin.fir.resolve.calls.ConeCompositeConflictResolver +import org.jetbrains.kotlin.fir.resolve.calls.ConeIntegerOperatorConflictResolver +import org.jetbrains.kotlin.fir.resolve.calls.ConeOverloadConflictResolver +import org.jetbrains.kotlin.fir.resolve.calls.jvm.ConeEquivalentCallConflictResolver +import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents +import org.jetbrains.kotlin.fir.types.typeContext +import org.jetbrains.kotlin.js.resolve.JsTypeSpecificityComparatorWithoutDelegate +import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator + +@NoMutableState +object JsCallConflictResolverFactory : ConeCallConflictResolverFactory() { + override fun create( + typeSpecificityComparator: TypeSpecificityComparator, + components: InferenceComponents, + transformerComponents: BodyResolveComponents + ): ConeCompositeConflictResolver { + val specificityComparator = JsTypeSpecificityComparatorWithoutDelegate(components.session.typeContext) + return ConeCompositeConflictResolver( + ConeOverloadConflictResolver(specificityComparator, components, transformerComponents), + ConeEquivalentCallConflictResolver(specificityComparator, components, transformerComponents), + ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents) + ) + } +} 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 743bce6b8e0..b876c78f05a 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 @@ -153,13 +153,13 @@ 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.mapTo(result) { System.getProperty("kotlin.js.$it.path") } + names.mapNotNullTo(result) { System.getProperty("kotlin.js.$it.path") } val runtimeClasspaths = testServices.runtimeClasspathProviders.flatMap { it.runtimeClassPaths(module) } runtimeClasspaths.mapTo(result) { it.absolutePath } return result } - fun getDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List { + fun getKlibDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List { val visited = mutableSetOf() fun getRecursive(module: TestModule, kind: DependencyRelation) { val dependencies = if (kind == DependencyRelation.FriendDependency) module.friendDependencies else module.regularDependencies @@ -171,8 +171,11 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu } } getRecursive(module, kind) - return visited - .map { testServices.dependencyProvider.getArtifact(it, ArtifactKinds.KLib).outputFile } + return visited.map { testServices.dependencyProvider.getArtifact(it, ArtifactKinds.KLib).outputFile } + } + + fun getDependencies(module: TestModule, testServices: TestServices, kind: DependencyRelation): List { + return getKlibDependencies(module, testServices, kind) .map { testServices.jsLibraryProvider.getDescriptorByPath(it.absolutePath) } } 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 0ce3b623c72..08b0ad23d85 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 @@ -6,6 +6,9 @@ package org.jetbrains.kotlin.js.analyze import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.search.DelegatingGlobalSearchScope +import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsTypeSpecificityComparator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsTypeSpecificityComparator.kt index f0affe5f169..e6cd7e706e0 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsTypeSpecificityComparator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsTypeSpecificityComparator.kt @@ -24,8 +24,13 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate -class JsTypeSpecificityComparator(val context: TypeSystemInferenceExtensionContextDelegate) : TypeSpecificityComparator { +// Replacing the TypeSystemInferenceExtensionContextDelegate with +// TypeSystemInferenceExtensionContext here leads to clashed registrations +// (for example, when trying to run IrJsTextTestCaseGenerated). +class JsTypeSpecificityComparator(context: TypeSystemInferenceExtensionContextDelegate) : + TypeSpecificityComparator by JsTypeSpecificityComparatorWithoutDelegate(context) +class JsTypeSpecificityComparatorWithoutDelegate(val context: TypeSystemInferenceExtensionContext) : TypeSpecificityComparator { private fun TypeSystemInferenceExtensionContext.checkOnlyDynamicFlexibleType(type: KotlinTypeMarker) { if (type.asFlexibleType() != null) { assert(type.isDynamic()) {