diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java index e53929192c9..644f3f0f4be 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java @@ -104,6 +104,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments { @Argument(value = "Xadd-compiler-builtins", description = "Add definitions of built-in declarations to the compilation classpath (useful with -no-stdlib)") public boolean addCompilerBuiltIns; + @Argument(value = "Xload-builtins-from-dependencies", description = "Load definitions of built-in declarations from module dependencies, instead of from the compiler") + public boolean loadBuiltInsFromDependencies; + @Argument(value = "Xinterface-compatibility", description = "Generate DefaultImpls classes for interfaces in JVM target bytecode version 1.8 for binary compatibility with 1.6") public boolean interfaceCompatibility; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 49c3ee7a0b6..45aedbf353c 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -334,6 +334,7 @@ class K2JVMCompiler : CLICompiler() { configuration.put(CLIConfigurationKeys.REPORT_PERF, arguments.reportPerf) configuration.put(JVMConfigurationKeys.USE_SINGLE_MODULE, arguments.singleModule) configuration.put(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES, arguments.addCompilerBuiltIns) + configuration.put(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES, arguments.loadBuiltInsFromDependencies) arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 34f376cd1da..8b55a2b0549 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.config; +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.kotlin.incremental.components.SourceRetentionAnnotationHandler; import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents; import org.jetbrains.kotlin.modules.Module; @@ -58,9 +59,23 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey USE_SINGLE_MODULE = CompilerConfigurationKey.create("combine modules for source files and binary dependencies into a single module"); + + /** + * Controls whether the module depends on an additional "built-ins" module, which contains binary metadata of built-in definitions. + * By default, that metadata is loaded from kotlin-compiler.jar. + * However, it can be also loaded directly from the module, see {@link CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES} + */ public static final CompilerConfigurationKey ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES = CompilerConfigurationKey.create("add built-ins from the compiler jar to the dependencies of the module being resolved"); + /** + * Controls whether an instance of KotlinBuiltIns which is passed to {@link ModuleDescriptorImpl}'s constructor and ends up being used + * everywhere in the compiler front-end is loaded directly from the module (from its sources and/or its binaries), as opposed to + * from kotlin-compiler.jar + */ + public static final CompilerConfigurationKey CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES = + CompilerConfigurationKey.create("create built-ins from resources found in the module dependencies"); + public static final CompilerConfigurationKey JVM_TARGET = CompilerConfigurationKey.create("JVM bytecode target version"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index bee9cfdebee..7225b1750a1 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -128,5 +128,9 @@ fun createContainerForTopDownAnalyzerForJvm( fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) { - get().initialize(module, languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) + get().initialize(module, languageVersionSettings) +} + +internal fun JvmBuiltIns.initialize(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) { + initialize(module, languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt index 631e5fe57c5..ba9fe426b68 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/TopDownAnalyzerFacadeForJVM.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDependenciesImpl import org.jetbrains.kotlin.frontend.java.di.createContainerForTopDownAnalyzerForJvm import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis +import org.jetbrains.kotlin.frontend.java.di.initialize import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver import org.jetbrains.kotlin.load.java.structure.JavaClass @@ -60,7 +61,6 @@ import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.utils.addToStdlib.check import java.util.* object TopDownAnalyzerFacadeForJVM { @@ -99,7 +99,8 @@ object TopDownAnalyzerFacadeForJVM { declarationProviderFactory: (StorageManager, Collection) -> DeclarationProviderFactory, sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files) ): ComponentProvider { - val moduleContext = createModuleContext(project, configuration) + val createBuiltInsFromModule = configuration.getBoolean(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES) + val moduleContext = createModuleContext(project, configuration, createBuiltInsFromModule) val storageManager = moduleContext.storageManager val module = moduleContext.module @@ -116,6 +117,14 @@ object TopDownAnalyzerFacadeForJVM { val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT) + val optionalBuiltInsModule = + if (configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES)) { + if (createBuiltInsFromModule) + JvmBuiltIns(storageManager).apply { initialize(module, languageVersionSettings) }.builtInsModule + else module.builtIns.builtInsModule + } + else null + val dependencyModule = if (separateModules) { val dependenciesContext = ContextForNewModule( moduleContext, Name.special(""), @@ -132,12 +141,7 @@ object TopDownAnalyzerFacadeForJVM { moduleClassResolver.compiledCodeResolver = dependenciesContainer.get() - dependenciesContext.setDependencies(listOfNotNull( - dependenciesContext.module, - dependenciesContext.module.builtIns.builtInsModule.check { - configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES) - } - )) + dependenciesContext.setDependencies(listOfNotNull(dependenciesContext.module, optionalBuiltInsModule)) dependenciesContext.initializeModuleContents(CompositePackageFragmentProvider(listOf( moduleClassResolver.compiledCodeResolver.packageFragmentProvider, dependenciesContainer.get() @@ -181,9 +185,7 @@ object TopDownAnalyzerFacadeForJVM { // TODO: remove dependencyModule from friends module.setDependencies(ModuleDependenciesImpl( - listOfNotNull(module, dependencyModule, module.builtIns.builtInsModule.check { - configuration.getBoolean(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES) - }), + listOfNotNull(module, dependencyModule, optionalBuiltInsModule), if (dependencyModule != null) setOf(dependencyModule) else emptySet() )) module.initialize(CompositePackageFragmentProvider( @@ -225,15 +227,23 @@ object TopDownAnalyzerFacadeForJVM { } fun createContextWithSealedModule(project: Project, configuration: CompilerConfiguration): MutableModuleContext = - createModuleContext(project, configuration).apply { + createModuleContext(project, configuration, false).apply { setDependencies(module, module.builtIns.builtInsModule) } - private fun createModuleContext(project: Project, configuration: CompilerConfiguration): MutableModuleContext { + private fun createModuleContext( + project: Project, + configuration: CompilerConfiguration, + createBuiltInsFromModule: Boolean + ): MutableModuleContext { val projectContext = ProjectContext(project) + val builtIns = JvmBuiltIns(projectContext.storageManager, !createBuiltInsFromModule) return ContextForNewModule( - projectContext, Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), - JvmBuiltIns(projectContext.storageManager) - ) + projectContext, Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"), builtIns + ).apply { + if (createBuiltInsFromModule) { + builtIns.builtInsModule = module + } + } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt index 8c1fbdb7edc..9a4af897bca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt @@ -23,13 +23,14 @@ import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.calls.util.createFunctionType import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.createDynamicType @@ -38,9 +39,11 @@ import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.utils.Printer import java.util.* -class DynamicCallableDescriptors(builtIns: KotlinBuiltIns) { +class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: KotlinBuiltIns) { - val dynamicType = createDynamicType(builtIns) + val dynamicType by storageManager.createLazyValue { + createDynamicType(builtIns) + } fun createDynamicDescriptorScope(call: Call, owner: DeclarationDescriptor) = object : MemberScopeImpl() { override fun printScopeStructure(p: Printer) { diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 0bc22d98fe4..c7d3e63b1a3 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -10,6 +10,8 @@ where advanced options include: -Xdump-declarations-to Path to JSON file to dump Java to Kotlin declaration mappings -Xsingle-module Combine modules for source files and binary dependencies into a single module -Xadd-compiler-builtins Add definitions of built-in declarations to the compilation classpath (useful with -no-stdlib) + -Xload-builtins-from-dependencies + Load definitions of built-in declarations from module dependencies, instead of from the compiler -Xinterface-compatibility Generate DefaultImpls classes for interfaces in JVM target bytecode version 1.8 for binary compatibility with 1.6 -Xno-inline Disable method inlining -Xrepeat Repeat compilation (for performance analysis) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/builtins/JvmBuiltInClassDescriptorFactory.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/builtins/JvmBuiltInClassDescriptorFactory.kt index f4671ce44fa..f03cdce1302 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/builtins/JvmBuiltInClassDescriptorFactory.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/builtins/JvmBuiltInClassDescriptorFactory.kt @@ -31,7 +31,7 @@ class JvmBuiltInClassDescriptorFactory( ) : ClassDescriptorFactory { private val cloneable by storageManager.createLazyValue { ClassDescriptorImpl( - moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance().single(), + moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance().first(), CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType), SourceElement.NO_SOURCE ).apply { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt index 77f2e877951..7efb9b1db0f 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt @@ -26,7 +26,10 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.utils.sure -class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManager) { +class JvmBuiltIns @JvmOverloads constructor( + storageManager: StorageManager, + loadBuiltInsFromCurrentClassLoader: Boolean = true +) : KotlinBuiltIns(storageManager) { // Module containing JDK classes or having them among dependencies private var ownerModuleDescriptor: ModuleDescriptor? = null private var isAdditionalBuiltInsFeatureSupported: Boolean = true @@ -46,7 +49,9 @@ class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManage } init { - createBuiltInsModule() + if (loadBuiltInsFromCurrentClassLoader) { + createBuiltInsModule() + } } override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter = settings diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 6fe5e776a83..530202f7e76 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.builtins; +import kotlin.collections.CollectionsKt; import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; @@ -23,13 +24,16 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.*; +import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor; import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; +import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope; import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.serialization.deserialization.AdditionalClassPartsProvider; import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory; @@ -42,7 +46,6 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import java.io.InputStream; import java.util.*; -import static kotlin.collections.CollectionsKt.single; import static kotlin.collections.SetsKt.setOf; import static org.jetbrains.kotlin.builtins.PrimitiveType.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; @@ -137,6 +140,22 @@ public abstract class KotlinBuiltIns { builtInsModule.initialize(packageFragmentProvider); builtInsModule.setDependencies(builtInsModule); } + + public void setBuiltInsModule(@NotNull final ModuleDescriptorImpl module) { + storageManager.compute(new Function0() { + @Override + public Void invoke() { + if (builtInsModule != null) { + throw new AssertionError( + "Built-ins module is already set: " + builtInsModule + " (attempting to reset to " + module + ")" + ); + } + builtInsModule = module; + return null; + } + }); + } + @NotNull protected AdditionalClassPartsProvider getAdditionalClassPartsProvider() { return AdditionalClassPartsProvider.None.INSTANCE; @@ -153,14 +172,39 @@ public abstract class KotlinBuiltIns { } @NotNull - private static PackageFragmentDescriptor createPackage( + private PackageFragmentDescriptor createPackage( @NotNull PackageFragmentProvider fragmentProvider, @NotNull Map packageNameToPackageFragment, - @NotNull FqName packageFqName + @NotNull final FqName packageFqName ) { - PackageFragmentDescriptor packageFragment = single(fragmentProvider.getPackageFragments(packageFqName)); - packageNameToPackageFragment.put(packageFqName, packageFragment); - return packageFragment; + final List packageFragments = fragmentProvider.getPackageFragments(packageFqName); + + PackageFragmentDescriptor result = + packageFragments.isEmpty() + ? new EmptyPackageFragmentDescriptor(builtInsModule, packageFqName) + : packageFragments.size() == 1 + ? packageFragments.iterator().next() + : new PackageFragmentDescriptorImpl(builtInsModule, packageFqName) { + @NotNull + @Override + public MemberScope getMemberScope() { + return new ChainedMemberScope( + "built-in package " + packageFqName, + CollectionsKt.map( + packageFragments, + new Function1() { + @Override + public MemberScope invoke(PackageFragmentDescriptor descriptor) { + return descriptor.getMemberScope(); + } + } + ) + ); + } + }; + + packageNameToPackageFragment.put(packageFqName, result); + return result; } @NotNull @@ -354,7 +398,9 @@ public abstract class KotlinBuiltIns { @NotNull private static ClassDescriptor getBuiltInClassByName(@NotNull Name simpleName, @NotNull PackageFragmentDescriptor packageFragment) { ClassDescriptor classDescriptor = getBuiltInClassByNameNullable(simpleName, packageFragment); - assert classDescriptor != null : "Built-in class " + simpleName + " is not found"; + if (classDescriptor == null) { + throw new AssertionError("Built-in class " + packageFragment.getFqName().child(simpleName).asString() + " is not found"); + } return classDescriptor; } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/BuiltInFictitiousFunctionClassFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/BuiltInFictitiousFunctionClassFactory.kt index b87a78b704a..d8bff6048c0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/BuiltInFictitiousFunctionClassFactory.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/BuiltInFictitiousFunctionClassFactory.kt @@ -80,7 +80,7 @@ class BuiltInFictitiousFunctionClassFactory( val packageFqName = classId.packageFqName val (kind, arity) = parseClassName(className, packageFqName) ?: return null - val containingPackageFragment = module.getPackage(packageFqName).fragments.filterIsInstance().single() + val containingPackageFragment = module.getPackage(packageFqName).fragments.filterIsInstance().first() return FunctionClassDescriptor(storageManager, containingPackageFragment, kind, arity) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt index 96dc7cb0a45..a1a2e90458a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionClassDescriptor.kt @@ -131,7 +131,7 @@ class FunctionClassDescriptor( // For KFunction{n}, add corresponding numbered Function{n} class, e.g. Function2 for KFunction2 if (functionKind == Kind.KFunction) { val packageView = containingDeclaration.containingDeclaration.getPackage(BUILT_INS_PACKAGE_FQ_NAME) - val kotlinPackageFragment = packageView.fragments.filterIsInstance().single() + val kotlinPackageFragment = packageView.fragments.filterIsInstance().first() add(kotlinPackageFragment, Kind.Function.numberedClassName(arity)) }