diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt index 3a452cccb7e..ef1fbbd5376 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt @@ -142,7 +142,7 @@ object TopDownAnalyzerFacadeForJVM { val jvmTarget = configuration.get(JVMConfigurationKeys.JVM_TARGET, JvmTarget.DEFAULT) val languageVersionSettings = configuration.languageVersionSettings - val fallbackBuiltIns = JvmBuiltIns(storageManager, loadBuiltInsFromCurrentClassLoader = true, isFallback = true).apply { + val fallbackBuiltIns = JvmBuiltIns(storageManager, JvmBuiltIns.Kind.FALLBACK).apply { initialize(builtInsModule, languageVersionSettings) }.builtInsModule @@ -269,7 +269,7 @@ object TopDownAnalyzerFacadeForJVM { private fun createModuleContext(project: Project, configuration: CompilerConfiguration): MutableModuleContext { val projectContext = ProjectContext(project) - val builtIns = JvmBuiltIns(projectContext.storageManager, false) + val builtIns = JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_DEPENDENCIES) return ContextForNewModule( projectContext, Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), builtIns, null ).apply { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatform.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatform.kt index a4064350e4a..52a11d02b9d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatform.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatform.kt @@ -32,7 +32,7 @@ object JvmPlatform : TargetPlatform("JVM") { } } - for (builtInPackage in JvmBuiltIns(storageManager).builtInPackagesImportedByDefault) { + for (builtInPackage in JvmBuiltIns(storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).builtInPackagesImportedByDefault) { addAllClassifiersFromScope(builtInPackage.memberScope) } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt index 6be8f0af019..0f292f78fdb 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt @@ -587,7 +587,8 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() { val platform = if (nameSuffix.isEmpty()) null else if (nameSuffix == "common") MultiTargetPlatform.Common else MultiTargetPlatform.Specific(nameSuffix.toUpperCase()) - return ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, JvmBuiltIns(storageManager), platform) + val builtIns = JvmBuiltIns(storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER) + return ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, builtIns, platform) } protected open fun createSealedModule(storageManager: StorageManager): ModuleDescriptorImpl = diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt index a96030dfb9c..ed47e2668db 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt @@ -63,7 +63,7 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() { val environment = createEnvironment(moduleDirs) val modules = setupModules(environment, moduleDirs) val projectContext = ProjectContext(environment.project) - val builtIns = JvmBuiltIns(projectContext.storageManager) + val builtIns = JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER) val resolverForProject = ResolverForProjectImpl( "test", projectContext, modules, diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt index e55904234ca..c8eb5d02225 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt @@ -13,12 +13,46 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.utils.sure -class JvmBuiltIns @JvmOverloads constructor( - storageManager: StorageManager, - loadBuiltInsFromCurrentClassLoader: Boolean = true, - // TODO: change this value to loadBuiltInsFromCurrentClassLoader as soon as built-ins are loaded from module dependencies everywhere - isFallback: Boolean = false -) : KotlinBuiltIns(storageManager) { +class JvmBuiltIns(storageManager: StorageManager, kind: Kind) : KotlinBuiltIns(storageManager) { + /** + * Where built-ins should be loaded from. + */ + enum class Kind { + /** + * Load built-ins from dependencies of the module that's being compiled. In this case, any request to a built-in class such as + * `kotlin.String` would end up querying contents of the module and all its dependencies in order until the first one returns + * anything, similarly to how it's done for normal (.class file-based) dependencies. If there's a class with FQ name `kotlin.String` + * in module sources, it'll be returned in [KotlinBuiltIns.getString], otherwise it'll be loaded from the first dependency that + * has the `kotlin/kotlin.kotlin_builtins` file where metadata of `kotlin.String` is located. + * + * If this mode is selected, the module should be injected after an instance of [JvmBuiltIns] is created via setting + * [KotlinBuiltIns.builtInsModule] to point to the module that's being compiled. + * + * This mode is preferred and should be used in new code when possible. + */ + FROM_DEPENDENCIES, + + /** + * Load built-ins by looking up `.kotlin_builtins` resources in the class loader of the current compiler or IDE plugin. + * + * This mode is discouraged and should be avoided when possible. The reason is that in case versions of the compiler and the + * standard library in compilation dependencies do not match, there can be tricky errors or even differences in behavior if + * built-ins API has changed. + */ + FROM_CLASS_LOADER, + + /** + * Similarly to [FROM_CLASS_LOADER], load built-ins from the compiler class loader, but also mark the loaded package + * fragments as "fallback" (`BuiltInsPackageFragment.isFallback`) to make the compiler report errors on any usages of elements + * from these built-ins. + * + * This mode is useful as a "secondary" built-ins source to ensure there are at least some built-ins for the compiler frontend to + * work correctly. Such fallback built-ins are usually placed at the end of the dependencies list, so that built-ins from the + * standard library (which are present in >99% cases) would win in the resolution. + */ + FALLBACK, + } + // Module containing JDK classes or having them among dependencies private var ownerModuleDescriptor: ModuleDescriptor? = null private var isAdditionalBuiltInsFeatureSupported: Boolean = true @@ -41,8 +75,11 @@ class JvmBuiltIns @JvmOverloads constructor( } init { - if (loadBuiltInsFromCurrentClassLoader) { - createBuiltInsModule(isFallback) + when (kind) { + Kind.FROM_DEPENDENCIES -> { + } + Kind.FROM_CLASS_LOADER -> createBuiltInsModule(false) + Kind.FALLBACK -> createBuiltInsModule(true) } } diff --git a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt index 97e3f97ee9c..12a6d6970fe 100644 --- a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt @@ -57,7 +57,7 @@ class RuntimeModuleData private constructor( companion object { fun create(classLoader: ClassLoader): RuntimeModuleData { val storageManager = LockBasedStorageManager("RuntimeModuleData") - val builtIns = JvmBuiltIns(storageManager, false) + val builtIns = JvmBuiltIns(storageManager, JvmBuiltIns.Kind.FROM_DEPENDENCIES) val module = ModuleDescriptorImpl(Name.special(""), storageManager, builtIns) builtIns.builtInsModule = module @@ -93,8 +93,8 @@ class RuntimeModuleData private constructor( RuntimeErrorReporter, LookupTracker.DO_NOTHING, ContractDeserializer.DEFAULT ) val builtinsProvider = JvmBuiltInsPackageFragmentProvider( - storageManager, reflectKotlinClassFinder, module, notFoundClasses, builtIns.settings, builtIns.settings, - DeserializationConfiguration.Default + storageManager, reflectKotlinClassFinder, module, notFoundClasses, builtIns.settings, builtIns.settings, + DeserializationConfiguration.Default ) singleModuleClassResolver.resolver = javaDescriptorResolver diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt index f1868fe7318..cbb95815347 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt @@ -29,7 +29,9 @@ class JvmPlatformKindResolution : IdePlatformKindResolution { override val resolverForModuleFactory: ResolverForModuleFactory get() = JvmAnalyzerFacade - override fun createBuiltIns(settings: PlatformAnalysisSettings, projectContext: ProjectContext): KotlinBuiltIns { - return if (settings.sdk != null) JvmBuiltIns(projectContext.storageManager) else DefaultBuiltIns.Instance - } -} \ No newline at end of file + override fun createBuiltIns(settings: PlatformAnalysisSettings, projectContext: ProjectContext): KotlinBuiltIns = + if (settings.sdk != null) + JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER) + else + DefaultBuiltIns.Instance +}