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:
Alexander Udalov
2017-07-14 20:07:01 +03:00
parent 8ce7742e7c
commit ed86757817
35 changed files with 179 additions and 132 deletions
@@ -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
}
@@ -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)
}
}
}
@@ -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(