Rework how built-in types are loaded in compiler for JVM
In TopDownAnalyzerFacadeForJVM, we now always use the "load built-ins from module dependencies" behavior that was previously only enabled with the dedicated CLI argument -Xload-builtins-from-dependencies. However, sometimes we compile code without kotlin-stdlib in the classpath, and we don't want everything to crash because some standard type like kotlin.Unit hasn't been found. To mitigate this, we add another module at the end of the dependencies list, namely a "fallback built-ins" module. This module loads all built-in declarations from the compiler's class loader, as was done by default previously. This prevents the compiler from crashing if any built-in declaration is not found, but compiling the code against built-ins found in the compiler is still discouraged, so we report an error if anything is resolved to a declaration from this module, via a new checker MissingBuiltInDeclarationChecker. Also introduce a new CLI argument -Xsuppress-missing-builtins-error specifically to suppress this error and to allow compiling code against compiler's own built-ins. #KT-19227 Fixed #KT-28198 Fixed
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.config;
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
|
||||
import org.jetbrains.kotlin.load.java.JavaClassesTracker;
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents;
|
||||
import org.jetbrains.kotlin.modules.Module;
|
||||
@@ -75,22 +74,6 @@ 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<Boolean> SKIP_RUNTIME_VERSION_CHECK =
|
||||
CompilerConfigurationKey.create("do not perform checks on runtime versions consistency");
|
||||
|
||||
|
||||
@@ -20,4 +20,7 @@ object JvmAnalysisFlags {
|
||||
|
||||
@JvmStatic
|
||||
val sanitizeParentheses by AnalysisFlag.Delegates.Boolean
|
||||
|
||||
@JvmStatic
|
||||
val suppressMissingBuiltinsError by AnalysisFlag.Delegates.Boolean
|
||||
}
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.jvm.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
|
||||
import org.jetbrains.kotlin.config.JvmAnalysisFlags
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
object MissingBuiltInDeclarationChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
if (context.languageVersionSettings.getFlag(JvmAnalysisFlags.suppressMissingBuiltinsError)) return
|
||||
|
||||
val descriptor = resolvedCall.resultingDescriptor
|
||||
val error = diagnosticFor(descriptor, reportOn)
|
||||
?: diagnosticFor(descriptor.returnType?.takeUnless(this::isComputingDeferredType)?.constructor?.declarationDescriptor, reportOn)
|
||||
error?.let(context.trace::report)
|
||||
}
|
||||
|
||||
private fun diagnosticFor(descriptor: DeclarationDescriptor?, reportOn: PsiElement): Diagnostic? {
|
||||
if (descriptor == null) return null
|
||||
|
||||
val containingClassOrPackage = DescriptorUtils.getParentOfType(descriptor, ClassOrPackageFragmentDescriptor::class.java)
|
||||
|
||||
if (containingClassOrPackage is ClassDescriptor) {
|
||||
val containingPackage = DescriptorUtils.getParentOfType(descriptor, PackageFragmentDescriptor::class.java)
|
||||
if ((containingPackage as? BuiltInsPackageFragment)?.isFallback == true) {
|
||||
return Errors.MISSING_BUILT_IN_DECLARATION.on(reportOn, containingClassOrPackage.fqNameSafe)
|
||||
}
|
||||
} else if (containingClassOrPackage is BuiltInsPackageFragment && containingClassOrPackage.isFallback) {
|
||||
return Errors.MISSING_BUILT_IN_DECLARATION.on(reportOn, descriptor.fqNameSafe)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
object ClassifierUsage : ClassifierUsageChecker {
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
if (context.languageVersionSettings.getFlag(JvmAnalysisFlags.suppressMissingBuiltinsError)) return
|
||||
|
||||
diagnosticFor(targetDescriptor, element)?.let(context.trace::report)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -42,6 +42,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
),
|
||||
|
||||
additionalCallCheckers = listOf(
|
||||
MissingBuiltInDeclarationChecker,
|
||||
JavaAnnotationCallChecker(),
|
||||
SuspensionPointInsideMutexLockChecker(),
|
||||
JavaClassOnCompanionChecker(),
|
||||
@@ -63,7 +64,8 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
),
|
||||
|
||||
additionalClassifierUsageCheckers = listOf(
|
||||
BigFunctionTypeAvailabilityChecker
|
||||
BigFunctionTypeAvailabilityChecker,
|
||||
MissingBuiltInDeclarationChecker.ClassifierUsage
|
||||
),
|
||||
|
||||
additionalAnnotationCheckers = listOf(
|
||||
|
||||
Reference in New Issue
Block a user