diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt index bc8add4324a..602f2f61a19 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmReflectionAPICallChecker.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.resolve.calls.checkers.AbstractReflectionApiCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH +import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue @@ -30,7 +31,11 @@ import org.jetbrains.kotlin.storage.getValue * If there's no Kotlin reflection implementation found in the classpath, checks that there are no usages * of reflection API which will fail at runtime. */ -class JvmReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : AbstractReflectionApiCallChecker(module, storageManager) { +class JvmReflectionAPICallChecker( + private val module: ModuleDescriptor, + notFoundClasses: NotFoundClasses, + storageManager: StorageManager +) : AbstractReflectionApiCallChecker(module, notFoundClasses, storageManager) { override val isWholeReflectionApiAvailable by storageManager.createLazyValue { module.findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) != null } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt index a8f6d13e569..a756845aed3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AbstractReflectionApiCallChecker.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.util.OperatorNameConventions @@ -34,12 +35,16 @@ private val ANY_MEMBER_NAMES = setOf("equals", "hashCode", "toString") /** * Checks that there are no usages of reflection API which will fail at runtime. */ -abstract class AbstractReflectionApiCallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : CallChecker { +abstract class AbstractReflectionApiCallChecker( + private val module: ModuleDescriptor, + private val notFoundClasses: NotFoundClasses, + storageManager: StorageManager +) : CallChecker { protected abstract val isWholeReflectionApiAvailable: Boolean protected abstract fun report(element: PsiElement, context: CallCheckerContext) private val kPropertyClasses by storageManager.createLazyValue { - val reflectionTypes = ReflectionTypes(module) + val reflectionTypes = ReflectionTypes(module, notFoundClasses) setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 931f728a726..05057a34711 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -120,9 +120,6 @@ class DoubleColonExpressionResolver( val variance = if (result is DoubleColonLHS.Expression && !result.isObjectQualifier) Variance.OUT_VARIANCE else Variance.INVARIANT val kClassType = reflectionTypes.getKClassType(Annotations.EMPTY, type, variance) - if (kClassType.isError) { - c.trace.report(MISSING_DEPENDENCY_CLASS.on(expression.receiverExpression!!, KotlinBuiltIns.FQ_NAMES.kClass.toSafe())) - } return dataFlowAnalyzer.checkType(createTypeInfo(kClassType, dataFlowInfo), expression, c) } } @@ -535,9 +532,6 @@ class DoubleColonExpressionResolver( checkReferenceIsToAllowedMember(descriptor, context.trace, expression) val type = createKCallableTypeForReference(descriptor, lhs, reflectionTypes, context.scope.ownerDescriptor) ?: return null - if (type.isError) { - context.trace.report(MISSING_DEPENDENCY_CLASS.on(expression, KotlinBuiltIns.FQ_NAMES.kCallable.toSafe())) - } when (descriptor) { is FunctionDescriptor -> bindFunctionReference(expression, type, context) @@ -580,13 +574,10 @@ class DoubleColonExpressionResolver( /* isCoroutine = */ false ) - val parameterTypes = if (type.isError) emptyList() else type.arguments.dropLast(1) - val returnType = if (type.isError) null else type.arguments.last().type - functionDescriptor.initialize( null, null, emptyList(), - createValueParametersForInvokeInFunctionType(functionDescriptor, parameterTypes), - returnType, + createValueParametersForInvokeInFunctionType(functionDescriptor, type.arguments.dropLast(1)), + type.arguments.last().type, Modality.FINAL, Visibilities.PUBLIC ) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt index 898a5071ad2..a0ccfdc7011 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses +import org.jetbrains.kotlin.storage.LockBasedStorageManager class GeneratorContext( val configuration: Psi2IrConfiguration, @@ -31,6 +33,6 @@ class GeneratorContext( ) : IrGeneratorContext(IrBuiltIns(moduleDescriptor.builtIns)) { val sourceManager = PsiSourceManager() - val reflectionTypes = ReflectionTypes(moduleDescriptor) + // TODO: inject a correct StorageManager instance, or store NotFoundClasses inside ModuleDescriptor + val reflectionTypes = ReflectionTypes(moduleDescriptor, NotFoundClasses(LockBasedStorageManager.NO_LOCKS, moduleDescriptor)) } - diff --git a/compiler/testData/cli/jvm/noStdlib.kt b/compiler/testData/cli/jvm/noStdlib.kt index 73c9c89cddf..1fd608749a4 100644 --- a/compiler/testData/cli/jvm/noStdlib.kt +++ b/compiler/testData/cli/jvm/noStdlib.kt @@ -2,6 +2,7 @@ import kotlin.reflect.* fun foo() { String::class.primaryConstructor + Void::class ::foo.isExternal listOf(42) } diff --git a/compiler/testData/cli/jvm/noStdlib.out b/compiler/testData/cli/jvm/noStdlib.out index dc50f3644d1..e38779c55ed 100644 --- a/compiler/testData/cli/jvm/noStdlib.out +++ b/compiler/testData/cli/jvm/noStdlib.out @@ -1,13 +1,13 @@ compiler/testData/cli/jvm/noStdlib.kt:1:8: error: unresolved reference: kotlin import kotlin.reflect.* ^ -compiler/testData/cli/jvm/noStdlib.kt:4:5: error: cannot access class 'kotlin.reflect.KClass'. Check your module classpath for missing or conflicting dependencies +compiler/testData/cli/jvm/noStdlib.kt:4:19: error: unresolved reference: primaryConstructor String::class.primaryConstructor - ^ -compiler/testData/cli/jvm/noStdlib.kt:5:5: error: cannot access class 'kotlin.reflect.KCallable'. Check your module classpath for missing or conflicting dependencies + ^ +compiler/testData/cli/jvm/noStdlib.kt:6:11: error: unresolved reference: isExternal ::foo.isExternal - ^ -compiler/testData/cli/jvm/noStdlib.kt:6:5: error: unresolved reference: listOf + ^ +compiler/testData/cli/jvm/noStdlib.kt:7:5: error: unresolved reference: listOf listOf(42) ^ COMPILATION_ERROR diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt index f4b28e64e37..92cd8f0ff90 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt @@ -55,11 +55,13 @@ class RuntimeModuleData private constructor( val singleModuleClassResolver = SingleModuleClassResolver() val runtimePackagePartProvider = RuntimePackagePartProvider(classLoader) val javaResolverCache = JavaResolverCache.EMPTY + val notFoundClasses = NotFoundClasses(storageManager, module) val globalJavaResolverContext = JavaResolverComponents( storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver, ExternalAnnotationResolver.EMPTY, SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, javaResolverCache, JavaPropertyInitializerEvaluator.DoNothing, SamConversionResolver, RuntimeSourceElementFactory, singleModuleClassResolver, - runtimePackagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module, ReflectionTypes(module) + runtimePackagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module, + ReflectionTypes(module, notFoundClasses) ) val lazyJavaPackageFragmentProvider = LazyJavaPackageFragmentProvider(globalJavaResolverContext) @@ -68,7 +70,6 @@ class RuntimeModuleData private constructor( val javaDescriptorResolver = JavaDescriptorResolver(lazyJavaPackageFragmentProvider, javaResolverCache) val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver) - val notFoundClasses = NotFoundClasses(storageManager, module) val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl( module, notFoundClasses, storageManager, reflectKotlinClassFinder ) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt index 302fe997d4e..c0127e1b83e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt @@ -21,11 +21,13 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.MemberScope +import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies import org.jetbrains.kotlin.types.* import java.util.* @@ -33,41 +35,34 @@ import kotlin.reflect.KProperty val KOTLIN_REFLECT_FQ_NAME = FqName("kotlin.reflect") -class ReflectionTypes(module: ModuleDescriptor) { +class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: NotFoundClasses) { private val kotlinReflectScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) { module.getPackage(KOTLIN_REFLECT_FQ_NAME).memberScope } - fun find(className: String): ClassDescriptor { + private fun find(className: String, numberOfTypeParameters: Int): ClassDescriptor { val name = Name.identifier(className) return kotlinReflectScope.getContributedClassifier(name, NoLookupLocation.FROM_REFLECTION) as? ClassDescriptor - ?: ErrorUtils.createErrorClass(KOTLIN_REFLECT_FQ_NAME.child(name).asString()) + ?: notFoundClasses.getClass(ClassId(KOTLIN_REFLECT_FQ_NAME, name), listOf(numberOfTypeParameters)) } - private object ClassLookup { + private class ClassLookup(val numberOfTypeParameters: Int) { operator fun getValue(types: ReflectionTypes, property: KProperty<*>): ClassDescriptor { - return types.find(property.name.capitalize()) + return types.find(property.name.capitalize(), numberOfTypeParameters) } } - fun getKFunction(n: Int): ClassDescriptor = find("KFunction$n") + fun getKFunction(n: Int): ClassDescriptor = find("KFunction$n", n + 1) - val kClass: ClassDescriptor by ClassLookup - val kProperty0: ClassDescriptor by ClassLookup - val kProperty1: ClassDescriptor by ClassLookup - val kProperty2: ClassDescriptor by ClassLookup - val kMutableProperty0: ClassDescriptor by ClassLookup - val kMutableProperty1: ClassDescriptor by ClassLookup + val kClass: ClassDescriptor by ClassLookup(1) + val kProperty0: ClassDescriptor by ClassLookup(1) + val kProperty1: ClassDescriptor by ClassLookup(2) + val kProperty2: ClassDescriptor by ClassLookup(3) + val kMutableProperty0: ClassDescriptor by ClassLookup(1) + val kMutableProperty1: ClassDescriptor by ClassLookup(2) - fun getKClassType(annotations: Annotations, type: KotlinType, variance: Variance): KotlinType { - val descriptor = kClass - if (ErrorUtils.isError(descriptor)) { - return descriptor.defaultType - } - - val arguments = listOf(TypeProjectionImpl(variance, type)) - return KotlinTypeFactory.simpleNotNullType(annotations, descriptor, arguments) - } + fun getKClassType(annotations: Annotations, type: KotlinType, variance: Variance): KotlinType = + KotlinTypeFactory.simpleNotNullType(annotations, kClass, listOf(TypeProjectionImpl(variance, type))) fun getKFunctionType( annotations: Annotations, @@ -78,31 +73,20 @@ class ReflectionTypes(module: ModuleDescriptor) { builtIns: KotlinBuiltIns ): KotlinType { val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) - val classDescriptor = getKFunction(arguments.size - 1 /* return type */) - - if (ErrorUtils.isError(classDescriptor)) { - return classDescriptor.defaultType - } - return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments) } fun getKPropertyType(annotations: Annotations, receiverType: KotlinType?, returnType: KotlinType, mutable: Boolean): KotlinType { - val classDescriptor = - when { - receiverType != null -> when { - mutable -> kMutableProperty1 - else -> kProperty1 - } - else -> when { - mutable -> kMutableProperty0 - else -> kProperty0 - } - } - - if (ErrorUtils.isError(classDescriptor)) { - return classDescriptor.defaultType + val classDescriptor = when { + receiverType != null -> when { + mutable -> kMutableProperty1 + else -> kProperty1 + } + else -> when { + mutable -> kMutableProperty0 + else -> kProperty0 + } } val arguments = ArrayList(2) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt index e6e396ed75c..56a5e1c96e2 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt @@ -25,12 +25,18 @@ import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.checkers.AbstractReflectionApiCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue private val ALLOWED_KCLASS_MEMBERS = setOf("simpleName", "isInstance") -class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : AbstractReflectionApiCallChecker(module, storageManager) { +class JsReflectionAPICallChecker( + module: ModuleDescriptor, + private val reflectionTypes: ReflectionTypes, + notFoundClasses: NotFoundClasses, + storageManager: StorageManager +) : AbstractReflectionApiCallChecker(module, notFoundClasses, storageManager) { override val isWholeReflectionApiAvailable: Boolean get() = false @@ -38,7 +44,7 @@ class JsReflectionAPICallChecker(private val module: ModuleDescriptor, storageMa context.trace.report(UNSUPPORTED.on(element, "This reflection API is not supported yet in JavaScript")) } - private val kClass by storageManager.createLazyValue { ReflectionTypes(module).kClass } + private val kClass by storageManager.createLazyValue { reflectionTypes.kClass } override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean = super.isAllowedReflectionApi(descriptor, containingClass) ||