Support injecting custom module into KotlinBuiltIns

Provide a command-line option to load built-ins from the module and its
dependencies instead of looking for them in kotlin-compiler.jar; built-ins must
be found this way, or an error will be reported (or, most likely at this
moment, an exception will be thrown).

Note that this does not affect whether built-ins (loaded from one place or the
other) are added to the _dependencies_ of the module, this is controlled by
another option. The option added in this commit only makes the KotlinBuiltIns
instance which is used via ModuleDescriptor throughout the compiler front-end
(and also injected in a bunch of places) a sort of "helper" which always goes
to that same module to find descriptors for built-in classes
This commit is contained in:
Alexander Udalov
2016-11-07 19:01:42 +03:00
parent 7898e2447d
commit 8c65379711
12 changed files with 121 additions and 32 deletions
@@ -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;
@@ -334,6 +334,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
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) }
}
@@ -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<Boolean> 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<Boolean> 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<Boolean> CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES =
CompilerConfigurationKey.create("create built-ins from resources found in the module dependencies");
public static final CompilerConfigurationKey<JvmTarget> JVM_TARGET =
CompilerConfigurationKey.create("JVM bytecode target version");
@@ -128,5 +128,9 @@ fun createContainerForTopDownAnalyzerForJvm(
fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) {
get<JvmBuiltIns>().initialize(module, languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers))
get<JvmBuiltIns>().initialize(module, languageVersionSettings)
}
internal fun JvmBuiltIns.initialize(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings) {
initialize(module, languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers))
}
@@ -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<KtFile>) -> 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("<dependencies of ${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"),
@@ -132,12 +141,7 @@ object TopDownAnalyzerFacadeForJVM {
moduleClassResolver.compiledCodeResolver = dependenciesContainer.get<JavaDescriptorResolver>()
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<JvmBuiltInsPackageFragmentProvider>()
@@ -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
}
}
}
}
@@ -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) {
+2
View File
@@ -10,6 +10,8 @@ where advanced options include:
-Xdump-declarations-to <path> 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 <count> Repeat compilation (for performance analysis)
@@ -31,7 +31,7 @@ class JvmBuiltInClassDescriptorFactory(
) : ClassDescriptorFactory {
private val cloneable by storageManager.createLazyValue {
ClassDescriptorImpl(
moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance<BuiltInsPackageFragment>().single(),
moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance<BuiltInsPackageFragment>().first(),
CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType),
SourceElement.NO_SOURCE
).apply {
@@ -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
@@ -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<Void>() {
@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<FqName, PackageFragmentDescriptor> packageNameToPackageFragment,
@NotNull FqName packageFqName
@NotNull final FqName packageFqName
) {
PackageFragmentDescriptor packageFragment = single(fragmentProvider.getPackageFragments(packageFqName));
packageNameToPackageFragment.put(packageFqName, packageFragment);
return packageFragment;
final List<PackageFragmentDescriptor> 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<PackageFragmentDescriptor, MemberScope>() {
@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;
}
@@ -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<BuiltInsPackageFragment>().single()
val containingPackageFragment = module.getPackage(packageFqName).fragments.filterIsInstance<BuiltInsPackageFragment>().first()
return FunctionClassDescriptor(storageManager, containingPackageFragment, kind, arity)
}
@@ -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<BuiltInsPackageFragment>().single()
val kotlinPackageFragment = packageView.fragments.filterIsInstance<BuiltInsPackageFragment>().first()
add(kotlinPackageFragment, Kind.Function.numberedClassName(arity))
}