From 55f384cb04027eb6206adfccb39d0ed5fa75046d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 27 May 2020 15:54:06 +0200 Subject: [PATCH] Do not rely on descriptors in KTypeParameterImpl.equals/hashCode Descriptors are cached via weak references in moduleByClassLoader.kt and can be garbage-collected at any point. So relying on identity of descriptors in KTypeParameterImpl is dangerous because the same type parameter can be represented by different descriptors. For example, the test equalsOnFunctionParameters.kt was flaky before this change because of this issue, and that could be reproduced by running it a few hundred times in the same process. Instead, use the type parameter's container (which is either KClass or KCallable) and name, in equals/hashCode. KClass and KCallable already have equals/hashCode independent of descriptors, so this works in case the descriptor is invalidated. --- .../ir/FirBlackBoxCodegenTestGenerated.java | 15 +++++ .../typeParametersEqualsWithClearCaches.kt | 56 +++++++++++++++++++ .../typeParameters/innerGenericParameter.kt | 28 ++++++++++ .../javaGenericTypeConstructor.kt | 30 ++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 15 +++++ .../LightAnalysisModeTestGenerated.java | 15 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 15 +++++ .../reflect/jvm/internal/KCallableImpl.kt | 4 +- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 6 +- .../jvm/internal/KDeclarationContainerImpl.kt | 42 +++----------- .../kotlin/reflect/jvm/internal/KTypeImpl.kt | 2 +- .../jvm/internal/KTypeParameterImpl.kt | 45 ++++++++++++++- .../jvm/internal/KTypeParameterOwnerImpl.kt | 12 ++++ .../src/kotlin/reflect/jvm/internal/util.kt | 47 ++++++++++++---- 14 files changed, 279 insertions(+), 53 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt create mode 100644 compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt create mode 100644 compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt create mode 100644 core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterOwnerImpl.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 793a1c06c93..e03f9bf0fd3 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -26192,6 +26192,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsHashCode.kt"); } + @TestMetadata("typeParametersEqualsWithClearCaches.kt") + public void testTypeParametersEqualsWithClearCaches() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt"); + } + @TestMetadata("typeParametersToString.kt") public void testTypeParametersToString() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersToString.kt"); @@ -27078,6 +27083,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/typeParameters/declarationSiteVariance.kt"); } + @TestMetadata("innerGenericParameter.kt") + public void testInnerGenericParameter() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt"); + } + + @TestMetadata("javaGenericTypeConstructor.kt") + public void testJavaGenericTypeConstructor() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt"); + } + @TestMetadata("typeParametersAndNames.kt") public void testTypeParametersAndNames() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeParameters/typeParametersAndNames.kt"); diff --git a/compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt b/compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt new file mode 100644 index 00000000000..56f64ce43c1 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt @@ -0,0 +1,56 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT +// FILE: box.kt + +import kotlin.test.assertEquals + +inline fun check(message: String, generate: () -> Any?) { + val x1: Any? + val x2: Any? + try { + x1 = generate() + + // Force clear the internal maps, as if the weak values in them are garbage-collected. + kotlin.reflect.jvm.internal.ReflectionFactoryImpl.clearCaches() + + x2 = generate() + } catch (e: Throwable) { + throw AssertionError("Fail $message", e) + } + + assertEquals(x1, x2, "Fail equals $message") + assertEquals(x2, x1, "Fail equals $message") + assertEquals(x1.hashCode(), x2.hashCode(), "Fail hashCode $message") +} + +class C { + fun v(): V? = null + fun t(): T? = null + val U.u: U get() = this +} + +fun W.w() {} +val X.x: X get() = this + +fun box(): String { + check("T from C's typeParameters") { C::class.typeParameters.single() } + check("V from v's typeParameters") { C::class.members.single { it.name == "v" }.typeParameters.single() } + + check("V from v's returnType") { C::class.members.single { it.name == "v" }.returnType.classifier } + check("T from t's returnType") { C::class.members.single { it.name == "t" }.returnType.classifier } + check("U from u's parameter type") { C::class.members.single { it.name == "u" }.parameters[1].type.classifier } + + check("W from w's parameter type") { Any::w.parameters.single().type.classifier } + check("X from x's parameter type") { Any::x.parameters.single().type.classifier } + + check("Z from J's typeParameters") { J::class.typeParameters.single() } + check("Z from z's returnType") { J::class.members.single { it.name == "z" }.returnType.classifier } + + return "OK" +} + +// FILE: J.java + +public interface J { + Z z(); +} diff --git a/compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt b/compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt new file mode 100644 index 00000000000..56b10cc8e66 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt @@ -0,0 +1,28 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +import kotlin.reflect.KVariance +import kotlin.test.assertEquals + +class A { + inner class B { + fun test(u: U): T? = null + } +} + +fun box(): String { + val fn = A.B::class.members.single { it.name == "test" } + + val t = A::class.typeParameters.single() + val u = A.B::class.typeParameters.single() + + assertEquals("T", t.name) + assertEquals(KVariance.OUT, t.variance) + assertEquals("U", u.name) + assertEquals(KVariance.IN, u.variance) + + assertEquals(t, fn.returnType.classifier) + assertEquals(u, fn.parameters[1].type.classifier) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt b/compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt new file mode 100644 index 00000000000..4cd5b95533d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT +// FILE: test.kt + +import kotlin.reflect.KVariance +import kotlin.test.assertEquals + +fun box(): String { + val ctor = J::class.constructors.single() + val ab = ctor.typeParameters + assertEquals(2, ab.size, ab.toString()) + + assertEquals("A", ab[0].name) + assertEquals(KVariance.INVARIANT, ab[0].variance) + assertEquals("B", ab[1].name) + assertEquals(KVariance.INVARIANT, ab[1].variance) + + // TODO: currently fails with "AssertionError: Expected , actual " + // assertEquals(ab[0], ctor.parameters[0].type.classifier) + + assertEquals(ab[1], ctor.parameters[1].type.classifier) + + return "OK" +} + +// FILE: J.java + +public class J { + public J(A a, B b) {} +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index e24887c2835..2f8a1f68660 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -27778,6 +27778,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsHashCode.kt"); } + @TestMetadata("typeParametersEqualsWithClearCaches.kt") + public void testTypeParametersEqualsWithClearCaches() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt"); + } + @TestMetadata("typeParametersToString.kt") public void testTypeParametersToString() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersToString.kt"); @@ -28664,6 +28669,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/typeParameters/declarationSiteVariance.kt"); } + @TestMetadata("innerGenericParameter.kt") + public void testInnerGenericParameter() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt"); + } + + @TestMetadata("javaGenericTypeConstructor.kt") + public void testJavaGenericTypeConstructor() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt"); + } + @TestMetadata("typeParametersAndNames.kt") public void testTypeParametersAndNames() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeParameters/typeParametersAndNames.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b63f5f050cf..d871ad6de8a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -25412,6 +25412,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsHashCode.kt"); } + @TestMetadata("typeParametersEqualsWithClearCaches.kt") + public void testTypeParametersEqualsWithClearCaches() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt"); + } + @TestMetadata("typeParametersToString.kt") public void testTypeParametersToString() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersToString.kt"); @@ -26298,6 +26303,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/typeParameters/declarationSiteVariance.kt"); } + @TestMetadata("innerGenericParameter.kt") + public void testInnerGenericParameter() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt"); + } + + @TestMetadata("javaGenericTypeConstructor.kt") + public void testJavaGenericTypeConstructor() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt"); + } + @TestMetadata("typeParametersAndNames.kt") public void testTypeParametersAndNames() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeParameters/typeParametersAndNames.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 045334c0507..0fc4eba18b5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -26192,6 +26192,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsHashCode.kt"); } + @TestMetadata("typeParametersEqualsWithClearCaches.kt") + public void testTypeParametersEqualsWithClearCaches() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersEqualsWithClearCaches.kt"); + } + @TestMetadata("typeParametersToString.kt") public void testTypeParametersToString() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/typeParametersToString.kt"); @@ -27078,6 +27083,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeParameters/declarationSiteVariance.kt"); } + @TestMetadata("innerGenericParameter.kt") + public void testInnerGenericParameter() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/innerGenericParameter.kt"); + } + + @TestMetadata("javaGenericTypeConstructor.kt") + public void testJavaGenericTypeConstructor() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeParameters/javaGenericTypeConstructor.kt"); + } + @TestMetadata("typeParametersAndNames.kt") public void testTypeParametersAndNames() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeParameters/typeParametersAndNames.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index 0198cb7f41e..a1a1e5d723e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -20,7 +20,7 @@ import kotlin.reflect.jvm.internal.calls.Caller import kotlin.reflect.jvm.javaType import kotlin.reflect.jvm.jvmErasure -internal abstract class KCallableImpl : KCallable { +internal abstract class KCallableImpl : KCallable, KTypeParameterOwnerImpl { abstract val descriptor: CallableMemberDescriptor // The instance which is used to perform a positional call, i.e. `call` @@ -82,7 +82,7 @@ internal abstract class KCallableImpl : KCallable { get() = _returnType() private val _typeParameters = ReflectProperties.lazySoft { - descriptor.typeParameters.map(::KTypeParameterImpl) + descriptor.typeParameters.map { descriptor -> KTypeParameterImpl(this, descriptor) } } override val typeParameters: List diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 85f97b69323..7b3d9a8d99e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -40,7 +40,9 @@ import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass import org.jetbrains.kotlin.descriptors.runtime.structure.functionClassArity import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive -internal class KClassImpl(override val jClass: Class) : KDeclarationContainerImpl(), KClass, KClassifierImpl { +internal class KClassImpl( + override val jClass: Class +) : KDeclarationContainerImpl(), KClass, KClassifierImpl, KTypeParameterOwnerImpl { inner class Data : KDeclarationContainerImpl.Data() { val descriptor: ClassDescriptor by ReflectProperties.lazySoft { val classId = classId @@ -115,7 +117,7 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration } val typeParameters: List by ReflectProperties.lazySoft { - descriptor.declaredTypeParameters.map(::KTypeParameterImpl) + descriptor.declaredTypeParameters.map { descriptor -> KTypeParameterImpl(this@KClassImpl, descriptor) } } val supertypes: List by ReflectProperties.lazySoft { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt index a6a8de7b4f8..21144cd3a7a 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -17,7 +17,11 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.descriptors.runtime.components.RuntimeModuleData +import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass +import org.jetbrains.kotlin.descriptors.runtime.structure.createArrayType +import org.jetbrains.kotlin.descriptors.runtime.structure.safeClassLoader +import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.renderer.DescriptorRenderer @@ -25,11 +29,6 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope import java.lang.reflect.Constructor import java.lang.reflect.Method import kotlin.jvm.internal.ClassBasedDeclarationContainer -import org.jetbrains.kotlin.descriptors.runtime.components.RuntimeModuleData -import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass -import org.jetbrains.kotlin.descriptors.runtime.structure.createArrayType -import org.jetbrains.kotlin.descriptors.runtime.structure.safeClassLoader -import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer { abstract inner class Data { @@ -51,17 +50,10 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain abstract fun getLocalProperty(index: Int): PropertyDescriptor? protected fun getMembers(scope: MemberScope, belonginess: MemberBelonginess): Collection> { - val visitor = object : DeclarationDescriptorVisitorEmptyBodies, Unit>() { - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallableImpl<*> = - createProperty(descriptor) - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): KCallableImpl<*> = - KFunctionImpl(this@KDeclarationContainerImpl, descriptor) - + val visitor = object : CreateKCallableVisitor(this) { override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit): KCallableImpl<*> = - throw IllegalStateException("No constructors should appear in this scope: $descriptor") + throw IllegalStateException("No constructors should appear here: $descriptor") } - return scope.getContributedDescriptors().mapNotNull { descriptor -> if (descriptor is CallableMemberDescriptor && descriptor.visibility != Visibilities.INVISIBLE_FAKE && @@ -78,26 +70,6 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain member.kind.isReal == (this == DECLARED) } - private fun createProperty(descriptor: PropertyDescriptor): KPropertyImpl<*> { - val receiverCount = (descriptor.dispatchReceiverParameter?.let { 1 } ?: 0) + - (descriptor.extensionReceiverParameter?.let { 1 } ?: 0) - - when { - descriptor.isVar -> when (receiverCount) { - 0 -> return KMutableProperty0Impl(this, descriptor) - 1 -> return KMutableProperty1Impl(this, descriptor) - 2 -> return KMutableProperty2Impl(this, descriptor) - } - else -> when (receiverCount) { - 0 -> return KProperty0Impl(this, descriptor) - 1 -> return KProperty1Impl(this, descriptor) - 2 -> return KProperty2Impl(this, descriptor) - } - } - - throw KotlinReflectionInternalError("Unsupported property: $descriptor") - } - fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor { val match = LOCAL_PROPERTY_SIGNATURE.matchEntire(signature) if (match != null) { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt index c680419231f..3397cd2644c 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -63,7 +63,7 @@ internal class KTypeImpl( return KClassImpl(jClass) } - is TypeParameterDescriptor -> return KTypeParameterImpl(descriptor) + is TypeParameterDescriptor -> return KTypeParameterImpl(null, descriptor) is TypeAliasDescriptor -> TODO("Type alias classifiers are not yet supported") else -> return null } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt index 9331aed8c8f..1510ec531e6 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterImpl.kt @@ -16,14 +16,23 @@ package kotlin.reflect.jvm.internal +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass +import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import kotlin.jvm.internal.TypeParameterReference import kotlin.reflect.KType import kotlin.reflect.KTypeParameter import kotlin.reflect.KVariance -internal class KTypeParameterImpl(override val descriptor: TypeParameterDescriptor) : KTypeParameter, KClassifierImpl { +internal class KTypeParameterImpl( + container: KTypeParameterOwnerImpl?, + override val descriptor: TypeParameterDescriptor, +) : KTypeParameter, KClassifierImpl { override val name: String get() = descriptor.name.asString() @@ -45,11 +54,41 @@ internal class KTypeParameterImpl(override val descriptor: TypeParameterDescript override val isReified: Boolean get() = descriptor.isReified + private val container: KTypeParameterOwnerImpl = container ?: run { + when (val declaration = descriptor.containingDeclaration) { + is ClassDescriptor -> { + declaration.toKClassImpl() + } + is CallableMemberDescriptor -> { + val callableContainerClass = when (val callableContainer = declaration.containingDeclaration) { + is ClassDescriptor -> { + callableContainer.toKClassImpl() + } + else -> { + val deserializedMember = declaration as? DeserializedMemberDescriptor + ?: throw KotlinReflectionInternalError("Non-class callable descriptor must be deserialized: $declaration") + deserializedMember.getContainerClass().kotlin as KClassImpl<*> + } + } + declaration.accept(CreateKCallableVisitor(callableContainerClass), Unit) + } + else -> throw KotlinReflectionInternalError("Unknown type parameter container: $declaration") + } + } + + private fun ClassDescriptor.toKClassImpl(): KClassImpl<*> = + toJavaClass()?.kotlin as KClassImpl<*>? + ?: throw KotlinReflectionInternalError("Type parameter container is not resolved: $containingDeclaration") + + private fun DeserializedMemberDescriptor.getContainerClass(): Class<*> = + containerSource.safeAs()?.knownJvmBinaryClass.safeAs()?.klass + ?: throw KotlinReflectionInternalError("Container of deserialized member is not resolved: $this") + override fun equals(other: Any?) = - other is KTypeParameterImpl && descriptor == other.descriptor + other is KTypeParameterImpl && container == other.container && name == other.name override fun hashCode() = - descriptor.hashCode() + container.hashCode() * 31 + name.hashCode() override fun toString() = TypeParameterReference.toString(this) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterOwnerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterOwnerImpl.kt new file mode 100644 index 00000000000..76227d2909e --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeParameterOwnerImpl.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package kotlin.reflect.jvm.internal + +import kotlin.reflect.KTypeParameter + +interface KTypeParameterOwnerImpl { + val typeParameters: List +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt index 5eee08ee1dd..d8514da324e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -20,6 +20,14 @@ import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.descriptors.runtime.components.ReflectAnnotationSource +import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass +import org.jetbrains.kotlin.descriptors.runtime.components.RuntimeSourceElementFactory +import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass +import org.jetbrains.kotlin.descriptors.runtime.structure.ReflectJavaAnnotation +import org.jetbrains.kotlin.descriptors.runtime.structure.ReflectJavaClass +import org.jetbrains.kotlin.descriptors.runtime.structure.safeClassLoader import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion @@ -32,23 +40,16 @@ import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.classId +import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer +import java.lang.reflect.Type import kotlin.jvm.internal.FunctionReference import kotlin.jvm.internal.PropertyReference +import kotlin.reflect.KType import kotlin.reflect.KVisibility import kotlin.reflect.full.IllegalCallableAccessException import kotlin.reflect.jvm.internal.calls.createAnnotationInstance -import org.jetbrains.kotlin.descriptors.runtime.components.ReflectAnnotationSource -import org.jetbrains.kotlin.descriptors.runtime.components.ReflectKotlinClass -import org.jetbrains.kotlin.descriptors.runtime.components.RuntimeSourceElementFactory -import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass -import org.jetbrains.kotlin.descriptors.runtime.structure.ReflectJavaAnnotation -import org.jetbrains.kotlin.descriptors.runtime.structure.ReflectJavaClass -import org.jetbrains.kotlin.descriptors.runtime.structure.safeClassLoader -import org.jetbrains.kotlin.resolve.isInlineClassType -import java.lang.reflect.Type -import kotlin.reflect.KType internal val JVM_STATIC = FqName("kotlin.jvm.JvmStatic") @@ -217,3 +218,29 @@ internal fun defaultPrimitiveValue(type: Type): Any? = else -> throw UnsupportedOperationException("Unknown primitive: $type") } } else null + +internal open class CreateKCallableVisitor(private val container: KDeclarationContainerImpl) : + DeclarationDescriptorVisitorEmptyBodies, Unit>() { + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallableImpl<*> { + val receiverCount = (descriptor.dispatchReceiverParameter?.let { 1 } ?: 0) + + (descriptor.extensionReceiverParameter?.let { 1 } ?: 0) + + when { + descriptor.isVar -> when (receiverCount) { + 0 -> return KMutableProperty0Impl(container, descriptor) + 1 -> return KMutableProperty1Impl(container, descriptor) + 2 -> return KMutableProperty2Impl(container, descriptor) + } + else -> when (receiverCount) { + 0 -> return KProperty0Impl(container, descriptor) + 1 -> return KProperty1Impl(container, descriptor) + 2 -> return KProperty2Impl(container, descriptor) + } + } + + throw KotlinReflectionInternalError("Unsupported property: $descriptor") + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): KCallableImpl<*> = + KFunctionImpl(container, descriptor) +}