diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt b/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt index 5d74fd72ec9..812429c9f3c 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ProtoCompareGenerated.kt @@ -56,6 +56,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) return false } + if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) return false + + for(i in 0..old.getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) { + if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) return false + } + return true } enum class ProtoBufPackageKind { @@ -64,7 +70,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR TYPE_ALIAS_LIST, TYPE_TABLE, SINCE_KOTLIN_INFO_TABLE, - PACKAGE_MODULE_NAME + PACKAGE_MODULE_NAME, + PACKAGE_LOCAL_VARIABLE_LIST } fun difference(old: ProtoBuf.Package, new: ProtoBuf.Package): EnumSet { @@ -91,6 +98,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) result.add(ProtoBufPackageKind.PACKAGE_MODULE_NAME) } + if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST) + + for(i in 0..old.getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) { + if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST) + } + return result } @@ -147,6 +160,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) return false } + if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) return false + + for(i in 0..old.getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) { + if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) return false + } + return true } enum class ProtoBufClassKind { @@ -166,7 +185,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR TYPE_TABLE, SINCE_KOTLIN_INFO, SINCE_KOTLIN_INFO_TABLE, - CLASS_MODULE_NAME + CLASS_MODULE_NAME, + CLASS_LOCAL_VARIABLE_LIST } fun difference(old: ProtoBuf.Class, new: ProtoBuf.Class): EnumSet { @@ -224,6 +244,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) result.add(ProtoBufClassKind.CLASS_MODULE_NAME) } + if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST) + + for(i in 0..old.getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) { + if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST) + } + return result } @@ -1053,6 +1079,10 @@ fun ProtoBuf.Package.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) hashCode = 31 * hashCode + stringIndexes(getExtension(JvmProtoBuf.packageModuleName)) } + for(i in 0..getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) { + hashCode = 31 * hashCode + getExtension(JvmProtoBuf.packageLocalVariable, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } @@ -1125,6 +1155,10 @@ fun ProtoBuf.Class.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> hashCode = 31 * hashCode + stringIndexes(getExtension(JvmProtoBuf.classModuleName)) } + for(i in 0..getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) { + hashCode = 31 * hashCode + getExtension(JvmProtoBuf.classLocalVariable, i).hashCode(stringIndexes, fqNameIndexes) + } + return hashCode } diff --git a/build-common/test/org/jetbrains/kotlin/serialization/jvm/DebugJvmProtoBuf.java b/build-common/test/org/jetbrains/kotlin/serialization/jvm/DebugJvmProtoBuf.java index e9c9a889511..9930388703b 100644 --- a/build-common/test/org/jetbrains/kotlin/serialization/jvm/DebugJvmProtoBuf.java +++ b/build-common/test/org/jetbrains/kotlin/serialization/jvm/DebugJvmProtoBuf.java @@ -14,7 +14,9 @@ public final class DebugJvmProtoBuf { registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.isRaw); registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.typeParameterAnnotation); registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classModuleName); + registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classLocalVariable); registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageModuleName); + registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageLocalVariable); } public interface StringTableTypesOrBuilder extends // @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.jvm.StringTableTypes) @@ -4586,6 +4588,17 @@ public final class DebugJvmProtoBuf { .newFileScopedGeneratedExtension( java.lang.Integer.class, null); + public static final int CLASS_LOCAL_VARIABLE_FIELD_NUMBER = 102; + /** + * extend .org.jetbrains.kotlin.serialization.Class { ... } + */ + public static final + org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension< + org.jetbrains.kotlin.serialization.DebugProtoBuf.Class, + java.util.List> classLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessage + .newFileScopedGeneratedExtension( + org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.class, + org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.getDefaultInstance()); public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101; /** * extend .org.jetbrains.kotlin.serialization.Package { ... } @@ -4597,6 +4610,17 @@ public final class DebugJvmProtoBuf { .newFileScopedGeneratedExtension( java.lang.Integer.class, null); + public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102; + /** + * extend .org.jetbrains.kotlin.serialization.Package { ... } + */ + public static final + org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension< + org.jetbrains.kotlin.serialization.DebugProtoBuf.Package, + java.util.List> packageLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessage + .newFileScopedGeneratedExtension( + org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.class, + org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.getDefaultInstance()); private static final org.jetbrains.kotlin.protobuf.Descriptors.Descriptor internal_static_org_jetbrains_kotlin_serialization_jvm_StringTableTypes_descriptor; private static @@ -4678,9 +4702,15 @@ public final class DebugJvmProtoBuf { "g.jetbrains.kotlin.serialization.Annotat" + "ion:J\n\021class_module_name\022).org.jetbrains" + ".kotlin.serialization.Class\030e \001(\005B\004\230\265\030\001:" + - "N\n\023package_module_name\022+.org.jetbrains.k" + - "otlin.serialization.Package\030e \001(\005B\004\230\265\030\001B" + - "\022B\020DebugJvmProtoBuf" + "u\n\024class_local_variable\022).org.jetbrains." + + "kotlin.serialization.Class\030f \003(\0132,.org.j" + + "etbrains.kotlin.serialization.Property:N", + "\n\023package_module_name\022+.org.jetbrains.ko" + + "tlin.serialization.Package\030e \001(\005B\004\230\265\030\001:y" + + "\n\026package_local_variable\022+.org.jetbrains" + + ".kotlin.serialization.Package\030f \003(\0132,.or" + + "g.jetbrains.kotlin.serialization.Propert" + + "yB\022B\020DebugJvmProtoBuf" }; org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { @@ -4733,7 +4763,9 @@ public final class DebugJvmProtoBuf { isRaw.internalInit(descriptor.getExtensions().get(4)); typeParameterAnnotation.internalInit(descriptor.getExtensions().get(5)); classModuleName.internalInit(descriptor.getExtensions().get(6)); - packageModuleName.internalInit(descriptor.getExtensions().get(7)); + classLocalVariable.internalInit(descriptor.getExtensions().get(7)); + packageModuleName.internalInit(descriptor.getExtensions().get(8)); + packageLocalVariable.internalInit(descriptor.getExtensions().get(9)); org.jetbrains.kotlin.protobuf.ExtensionRegistry registry = org.jetbrains.kotlin.protobuf.ExtensionRegistry.newInstance(); registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt index 3da1657e76d..17ced65e860 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt @@ -175,8 +175,11 @@ class MultifileClassPartCodegen( } } - val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(v.serializationBindings, state)) - val packageProto = serializer.packagePartProto(packageFragment.fqName, members).build() + val extension = JvmSerializerExtension(v.serializationBindings, state) + val serializer = DescriptorSerializer.createTopLevel(extension) + val builder = serializer.packagePartProto(packageFragment.fqName, members) + extension.serializeJvmPackage(builder, partType) + val packageProto = builder.build() val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java index ad2d0cab7d4..5c2d2319564 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java @@ -119,9 +119,11 @@ public class PackagePartCodegen extends MemberCodegen { } } - DescriptorSerializer serializer = - DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), state)); - ProtoBuf.Package packageProto = serializer.packagePartProto(element.getPackageFqName(), members).build(); + JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state); + DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(extension); + ProtoBuf.Package.Builder builder = serializer.packagePartProto(element.getPackageFqName(), members); + extension.serializeJvmPackage(builder, packagePartType); + ProtoBuf.Package packageProto = builder.build(); WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, av -> { writeAnnotationData(av, serializer, packageProto); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/fakeDescriptorsForReferences.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/fakeDescriptorsForReferences.kt index 5b7554be92e..8cb9b87b295 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/fakeDescriptorsForReferences.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/fakeDescriptorsForReferences.kt @@ -17,14 +17,25 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.descriptors.* -import java.util.ArrayList +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import java.util.* /** * Given a function descriptor, creates another function descriptor with type parameters copied from outer context(s). * This is needed because once we're serializing this to a proto, there's no place to store information about external type parameters. */ fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor { - val builder = descriptor.newCopyBuilder() + return createFreeDescriptor(descriptor) +} + +private fun createFreeDescriptor(descriptor: D): D { + @Suppress("UNCHECKED_CAST") + val builder = descriptor.newCopyBuilder() as CallableMemberDescriptor.CopyBuilder + val typeParameters = ArrayList(0) builder.setTypeParameters(typeParameters) @@ -41,3 +52,32 @@ fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor): FunctionDesc return if (typeParameters.isEmpty()) descriptor else builder.build()!! } + +/** + * Given a local delegated variable descriptor, creates a descriptor of a property that should be observed + * when using reflection on that local variable at runtime. + * Only members used by [DescriptorSerializer.propertyProto] are implemented correctly in this property descriptor. + */ +fun createFreeFakeLocalPropertyDescriptor(descriptor: LocalVariableDescriptor): PropertyDescriptor { + val property = PropertyDescriptorImpl.create( + descriptor.containingDeclaration, descriptor.annotations, Modality.FINAL, descriptor.visibility, descriptor.isVar, + descriptor.name, CallableMemberDescriptor.Kind.DECLARATION, descriptor.source, false, descriptor.isConst, + false, false, false, @Suppress("DEPRECATION") descriptor.isDelegated + ) + property.setType(descriptor.type, descriptor.typeParameters, descriptor.dispatchReceiverParameter, descriptor.extensionReceiverParameter) + + property.initialize( + descriptor.getter?.run { + PropertyGetterDescriptorImpl(property, annotations, modality, visibility, true, isExternal, isInline, kind, null, source).apply { + initialize(this@run.returnType) + } + }, + descriptor.setter?.run { + PropertySetterDescriptorImpl(property, annotations, modality, visibility, true, isExternal, isInline, kind, null, source).apply { + initialize(this@run.valueParameters.single()) + } + } + ) + + return createFreeDescriptor(property) +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java index 3c06a2c0678..e6e71dd7d27 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java @@ -20,19 +20,22 @@ import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.ClassBuilderMode; +import org.jetbrains.kotlin.codegen.FakeDescriptorsForReferencesKt; +import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl; import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer; import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.serialization.AnnotationSerializer; -import org.jetbrains.kotlin.serialization.ProtoBuf; -import org.jetbrains.kotlin.serialization.SerializerExtension; -import org.jetbrains.kotlin.serialization.StringTable; +import org.jetbrains.kotlin.protobuf.GeneratedMessageLite; +import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.serialization.*; import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite; import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf; import org.jetbrains.kotlin.types.FlexibleType; @@ -40,10 +43,14 @@ import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.Method; +import java.util.List; + import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*; public class JvmSerializerExtension extends SerializerExtension { private final JvmSerializationBindings bindings; + private final BindingContext codegenBinding; + private final KotlinTypeMapper typeMapper; private final StringTable stringTable; private final AnnotationSerializer annotationSerializer; private final boolean useTypeTable; @@ -52,7 +59,9 @@ public class JvmSerializerExtension extends SerializerExtension { public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull GenerationState state) { this.bindings = bindings; - this.stringTable = new JvmStringTable(state.getTypeMapper()); + this.codegenBinding = state.getBindingContext(); + this.typeMapper = state.getTypeMapper(); + this.stringTable = new JvmStringTable(typeMapper); this.annotationSerializer = new AnnotationSerializer(stringTable); this.useTypeTable = state.getUseTypeTableInSerializer(); this.moduleName = state.getModuleName(); @@ -75,6 +84,8 @@ public class JvmSerializerExtension extends SerializerExtension { if (!moduleName.equals(JvmAbi.DEFAULT_MODULE_NAME)) { proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName)); } + + writeLocalProperties(proto, typeMapper.mapClass(descriptor), JvmProtoBuf.classLocalVariable); } @Override @@ -84,6 +95,29 @@ public class JvmSerializerExtension extends SerializerExtension { } } + public void serializeJvmPackage(@NotNull ProtoBuf.Package.Builder proto, @NotNull Type partAsmType) { + writeLocalProperties(proto, partAsmType, JvmProtoBuf.packageLocalVariable); + } + + private , + BuilderType extends GeneratedMessageLite.ExtendableBuilder> void writeLocalProperties( + @NotNull BuilderType proto, + @NotNull Type classAsmType, + @NotNull GeneratedMessageLite.GeneratedExtension> extension + ) { + List localVariables = codegenBinding.get(CodegenBinding.DELEGATED_PROPERTIES, classAsmType); + if (localVariables == null) return; + + for (VariableDescriptorWithAccessors localVariable : localVariables) { + if (localVariable instanceof LocalVariableDescriptor) { + PropertyDescriptor propertyDescriptor = + FakeDescriptorsForReferencesKt.createFreeFakeLocalPropertyDescriptor((LocalVariableDescriptor) localVariable); + DescriptorSerializer serializer = DescriptorSerializer.createForLambda(this); + proto.addExtension(extension, serializer.propertyProto(propertyDescriptor).build()); + } + } + } + @Override public void serializeFlexibleType( @NotNull FlexibleType flexibleType, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java index aedd6af2619..78aa8bab775 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java @@ -26,8 +26,8 @@ import org.jetbrains.kotlin.types.TypeSubstitutor; public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors { private final boolean isDelegated; - private VariableAccessorDescriptor getter; - private VariableAccessorDescriptor setter; + private LocalVariableAccessorDescriptor.Getter getter; + private LocalVariableAccessorDescriptor.Setter setter; public LocalVariableDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @@ -73,13 +73,13 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm @Nullable @Override - public VariableAccessorDescriptor getGetter() { + public LocalVariableAccessorDescriptor.Getter getGetter() { return getter; } @Nullable @Override - public VariableAccessorDescriptor getSetter() { + public LocalVariableAccessorDescriptor.Setter getSetter() { return setter; } diff --git a/compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt b/compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt new file mode 100644 index 00000000000..81d767b6cd8 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt @@ -0,0 +1,75 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.* + +object Delegate { + lateinit var property: KProperty<*> + + operator fun getValue(instance: Any?, kProperty: KProperty<*>): List { + property = kProperty + return emptyList() + } + + operator fun setValue(instance: Any?, kProperty: KProperty<*>, value: List) { + throw AssertionError() + } +} + +fun check(expectedName: String, p: KProperty0<*>): String? { + assertEquals(expectedName, p.name) + assertEquals(emptyList(), p.parameters) + assertEquals(emptyList(), p.typeParameters) + assertEquals(null, p.visibility) // "local" visibility is not representable with reflection API + assertEquals("kotlin.collections.List", p.returnType.toString()) + assertTrue(p.isFinal) + assertFalse(p.isOpen) + assertFalse(p.isAbstract) + assertFalse(p.isLateinit) + assertFalse(p.isConst) + + // TODO: support getDelegate for local delegated properties + assertEquals(null, (p as KProperty0<*>).getDelegate()) + + assertEquals(emptyList(), p.getter.parameters) + assertEquals("kotlin.collections.List", p.getter.returnType.toString()) + + // TODO: support annotations + assertEquals(emptyList(), p.annotations) + + try { + p.call() + return "Fail: reflective call of a local delegated property should fail because it's not supported" + } catch (e: UnsupportedOperationException) { /* ok */ } + + if (p is KMutableProperty0<*>) { + assertEquals(listOf("kotlin.collections.List"), p.setter.parameters.map { it.type.toString() }) + assertEquals("kotlin.Unit", p.setter.returnType.toString()) + + try { + p.setter.call() + return "Fail: reflective call of a local delegated property setter should fail because it's not supported" + } catch (e: UnsupportedOperationException) { /* ok */ } + } + + return null +} + +annotation class Anno + +fun box(): String { + @Anno + val localVal by Delegate + localVal + + check("localVal", Delegate.property as KProperty0<*>)?.let { error -> return error } + + @Anno + var localVar by Delegate + localVar + + check("localVar", Delegate.property as KProperty0<*>)?.let { error -> return error } + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt b/compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt new file mode 100644 index 00000000000..26178e76e8b --- /dev/null +++ b/compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt @@ -0,0 +1,43 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +// FILE: 1.kt + +@file:JvmMultifileClass +@file:JvmName("Test") + +package test + +import kotlin.reflect.* + +object Delegate { + lateinit var property: KProperty<*> + + operator fun getValue(instance: Any?, kProperty: KProperty<*>): List { + property = kProperty + return emptyList() + } +} + +// FILE: 2.kt + +@file:JvmMultifileClass +@file:JvmName("Test") + +package test + +fun foo() { + val x by Delegate + x +} + +// FILE: test.kt + +import test.* +import kotlin.test.assertEquals + +fun box(): String { + foo() + assertEquals("val x: kotlin.collections.List", Delegate.property.toString()) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt b/compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt new file mode 100644 index 00000000000..71e0440f6eb --- /dev/null +++ b/compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt @@ -0,0 +1,31 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.* + +class Delegate(val value: T) { + lateinit var property: KProperty<*> + + operator fun getValue(instance: Any?, kProperty: KProperty<*>): T { + property = kProperty + return value + } +} + +class A { + inner class B { + fun foo() { + val delegate = Delegate, Z>>(emptyMap()) + val c: Map, Z> by delegate + c + + assertEquals("kotlin.collections.Map, Z>", delegate.property.returnType.toString()) + } + } +} + +fun box(): String { + A().B().foo() + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 4f7fcabaf53..548b2ff753d 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -16041,6 +16041,33 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalDelegated extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInLocalDelegated() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("localDelegatedProperty.kt") + public void testLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt"); + doTest(fileName); + } + + @TestMetadata("multiFileClass.kt") + public void testMultiFileClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt"); + doTest(fileName); + } + + @TestMetadata("variableOfGenericType.kt") + public void testVariableOfGenericType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 0268074b66a..845c96629d5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16041,6 +16041,33 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalDelegated extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLocalDelegated() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("localDelegatedProperty.kt") + public void testLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt"); + doTest(fileName); + } + + @TestMetadata("multiFileClass.kt") + public void testMultiFileClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt"); + doTest(fileName); + } + + @TestMetadata("variableOfGenericType.kt") + public void testVariableOfGenericType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8a41b4537f6..076960d9855 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16041,6 +16041,33 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalDelegated extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInLocalDelegated() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("localDelegatedProperty.kt") + public void testLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt"); + doTest(fileName); + } + + @TestMetadata("multiFileClass.kt") + public void testMultiFileClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt"); + doTest(fileName); + } + + @TestMetadata("variableOfGenericType.kt") + public void testVariableOfGenericType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") diff --git a/core/descriptor.loader.java/src/jvm_descriptors.proto b/core/descriptor.loader.java/src/jvm_descriptors.proto index 811f9d1e2bb..8d3174d41b2 100644 --- a/core/descriptor.loader.java/src/jvm_descriptors.proto +++ b/core/descriptor.loader.java/src/jvm_descriptors.proto @@ -112,8 +112,12 @@ extend TypeParameter { extend Class { // If absent, assumed to be JvmAbi.DEFAULT_MODULE_NAME optional int32 class_module_name = 101 [(string_id_in_table) = true]; + + repeated Property class_local_variable = 102; } extend Package { optional int32 package_module_name = 101 [(string_id_in_table) = true]; + + repeated Property package_local_variable = 102; } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt index b6f8f9ca98b..0fadc8b0b49 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt @@ -29,7 +29,7 @@ class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) { companion object { @JvmField - val INSTANCE = JvmMetadataVersion(1, 1, 6) + val INSTANCE = JvmMetadataVersion(1, 1, 7) @JvmField val INVALID_VERSION = JvmMetadataVersion() diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/serialization/jvm/JvmProtoBuf.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/serialization/jvm/JvmProtoBuf.java index a67026ce258..0a5021d0978 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/serialization/jvm/JvmProtoBuf.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/serialization/jvm/JvmProtoBuf.java @@ -14,7 +14,9 @@ public final class JvmProtoBuf { registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.isRaw); registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.typeParameterAnnotation); registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classModuleName); + registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classLocalVariable); registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageModuleName); + registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageLocalVariable); } public interface StringTableTypesOrBuilder extends // @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.jvm.StringTableTypes) @@ -3901,6 +3903,22 @@ public final class JvmProtoBuf { 101, org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32, java.lang.Integer.class); + public static final int CLASS_LOCAL_VARIABLE_FIELD_NUMBER = 102; + /** + * extend .org.jetbrains.kotlin.serialization.Class { ... } + */ + public static final + org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension< + org.jetbrains.kotlin.serialization.ProtoBuf.Class, + java.util.List> classLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite + .newRepeatedGeneratedExtension( + org.jetbrains.kotlin.serialization.ProtoBuf.Class.getDefaultInstance(), + org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(), + null, + 102, + org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE, + false, + org.jetbrains.kotlin.serialization.ProtoBuf.Property.class); public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101; /** * extend .org.jetbrains.kotlin.serialization.Package { ... } @@ -3917,6 +3935,22 @@ public final class JvmProtoBuf { 101, org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32, java.lang.Integer.class); + public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102; + /** + * extend .org.jetbrains.kotlin.serialization.Package { ... } + */ + public static final + org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension< + org.jetbrains.kotlin.serialization.ProtoBuf.Package, + java.util.List> packageLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite + .newRepeatedGeneratedExtension( + org.jetbrains.kotlin.serialization.ProtoBuf.Package.getDefaultInstance(), + org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(), + null, + 102, + org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE, + false, + org.jetbrains.kotlin.serialization.ProtoBuf.Property.class); static { } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/CallableMemberDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/CallableMemberDescriptor.java index 28f0544f976..bd5603c2243 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/CallableMemberDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/CallableMemberDescriptor.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.types.TypeSubstitution; import java.util.Collection; +import java.util.List; public interface CallableMemberDescriptor extends CallableDescriptor, MemberDescriptor { @NotNull @@ -70,6 +71,9 @@ public interface CallableMemberDescriptor extends CallableDescriptor, MemberDesc @NotNull CopyBuilder setKind(@NotNull Kind kind); + @NotNull + CopyBuilder setTypeParameters(@NotNull List parameters); + @NotNull CopyBuilder setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java index 393f80ad231..c0051d74c62 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java @@ -117,6 +117,7 @@ public interface FunctionDescriptor extends CallableMemberDescriptor { CopyBuilder setValueParameters(@NotNull List parameters); @NotNull + @Override CopyBuilder setTypeParameters(@NotNull List parameters); @NotNull diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java index ab68cac1289..96837e55dcd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java @@ -237,24 +237,20 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp return newCopyBuilder() .setSubstitution(originalSubstitutor.getSubstitution()) - .setOwner(getContainingDeclaration()) - .setModality(modality) - .setVisibility(visibility) .setOriginal(getOriginal()) - .setCopyOverrides(true) - .setKind(getKind()) .build(); } public class CopyConfiguration implements PropertyDescriptor.CopyBuilder { - private DeclarationDescriptor owner; - private Modality modality; - private Visibility visibility; + private DeclarationDescriptor owner = getContainingDeclaration(); + private Modality modality = getModality(); + private Visibility visibility = getVisibility(); private PropertyDescriptor original = null; - private Kind kind; + private Kind kind = getKind(); private TypeSubstitution substitution = TypeSubstitution.EMPTY; private boolean copyOverrides = true; private ReceiverParameterDescriptor dispatchReceiverParameter = PropertyDescriptorImpl.this.dispatchReceiverParameter; + private List newTypeParameters = null; @NotNull @Override @@ -290,6 +286,13 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp return this; } + @NotNull + @Override + public CopyBuilder setTypeParameters(@NotNull List typeParameters) { + this.newTypeParameters = typeParameters; + return this; + } + @NotNull @Override public CopyConfiguration setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter) { @@ -330,7 +333,8 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp copyConfiguration.owner, copyConfiguration.modality, copyConfiguration.visibility, copyConfiguration.original, copyConfiguration.kind); - List originalTypeParameters = getTypeParameters(); + List originalTypeParameters = + copyConfiguration.newTypeParameters == null ? getTypeParameters() : copyConfiguration.newTypeParameters; List substitutedTypeParameters = new ArrayList(originalTypeParameters.size()); TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters( originalTypeParameters, copyConfiguration.substitution, substitutedDescriptor, substitutedTypeParameters diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt index ca678bfac67..44b2cef7bd4 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt @@ -36,6 +36,10 @@ internal object EmptyContainerForLocal : KDeclarationContainerImpl() { override fun getFunctions(name: Name): Collection = fail() - private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " + - "is not yet fully supported in Kotlin reflection") -} \ No newline at end of file + override fun getLocalProperty(index: Int): PropertyDescriptor? = null + + private fun fail(): Nothing = throw KotlinReflectionInternalError( + "Introspecting local functions, lambdas, anonymous functions and local variables " + + "is not yet fully supported in Kotlin reflection" + ) +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt index e1717f49165..157c537a811 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -268,6 +268,11 @@ internal abstract class FunctionCaller( } } + object ThrowingCaller : FunctionCaller(null, Void.TYPE, null, emptyArray()) { + override fun call(args: Array<*>): Any? { + throw UnsupportedOperationException("call/callBy are not supported for this declaration.") + } + } companion object { // TODO lazily allocate array at bound callers? 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 bf185f61d37..3465cf187a9 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -30,9 +30,13 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import org.jetbrains.kotlin.utils.compactIfPossible import kotlin.jvm.internal.TypeIntrinsics import kotlin.reflect.* +import kotlin.reflect.jvm.deserializeToDescriptor import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.INHERITED @@ -195,6 +199,14 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration memberScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) + staticScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) + override fun getLocalProperty(index: Int): PropertyDescriptor? { + return (descriptor as? DeserializedClassDescriptor)?.let { descriptor -> + val proto = descriptor.classProto.getExtension(JvmProtoBuf.classLocalVariable, index) + val nameResolver = descriptor.c.nameResolver + deserializeToDescriptor(jClass, proto, nameResolver, descriptor.c.typeTable, MemberDeserializer::loadProperty) + } + } + override val simpleName: String? get() = data().simpleName override val qualifiedName: String? get() = data().qualifiedName 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 fde05d29532..068c2041c04 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -45,6 +45,8 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain abstract fun getFunctions(name: Name): Collection + 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<*> = @@ -95,9 +97,15 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain } fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor { + val match = LOCAL_PROPERTY_SIGNATURE.matchEntire(signature) + if (match != null) { + val (number) = match.destructured + return getLocalProperty(number.toInt()) + ?: throw KotlinReflectionInternalError("Local property #$number not found in $jClass") + } + val properties = getProperties(Name.identifier(name)) .filter { descriptor -> - descriptor is PropertyDescriptor && RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature } @@ -279,5 +287,7 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain companion object { private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker") + + internal val LOCAL_PROPERTY_SIGNATURE = "".toRegex() } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 2b100f478f1..4e362844cae 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -24,8 +24,14 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.serialization.PackageData +import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer +import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil import kotlin.reflect.KCallable +import kotlin.reflect.jvm.deserializeToDescriptor import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED internal class KPackageImpl( @@ -33,7 +39,7 @@ internal class KPackageImpl( @Suppress("unused") val usageModuleName: String? = null // may be useful for debug ) : KDeclarationContainerImpl() { private inner class Data : KDeclarationContainerImpl.Data() { - val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft { + private val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft { // TODO: do not read ReflectKotlinClass multiple times ReflectKotlinClass.create(jClass) } @@ -57,6 +63,17 @@ internal class KPackageImpl( } } + val metadata: PackageData? by ReflectProperties.lazy { + kotlinClass?.classHeader?.let { header -> + val data = header.data + val strings = header.strings + if (data != null && strings != null) { + JvmProtoBufUtil.readPackageDataFrom(data, strings) + } + else null + } + } + val members: Collection> by ReflectProperties.lazySoft { getMembers(scope, DECLARED).filter { member -> val callableDescriptor = member.descriptor as DeserializedCallableMemberDescriptor @@ -84,6 +101,13 @@ internal class KPackageImpl( override fun getFunctions(name: Name): Collection = scope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) + override fun getLocalProperty(index: Int): PropertyDescriptor? { + return data().metadata?.let { (nameResolver, packageProto) -> + val proto = packageProto.getExtension(JvmProtoBuf.packageLocalVariable, index) + deserializeToDescriptor(jClass, proto, nameResolver, TypeTable(packageProto.typeTable), MemberDeserializer::loadProperty) + } + } + override fun equals(other: Any?): Boolean = other is KPackageImpl && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index d4e4a71e61d..5d0bd275290 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -178,12 +178,14 @@ internal abstract class KPropertyImpl private constructor( private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Boolean): FunctionCaller<*> { + if (KDeclarationContainerImpl.LOCAL_PROPERTY_SIGNATURE.matches(property.signature)) { + return FunctionCaller.ThrowingCaller + } + fun isInsideClassCompanionObject(): Boolean { val possibleCompanionObject = property.descriptor.containingDeclaration - if (DescriptorUtils.isCompanionObject(possibleCompanionObject) && !DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)) { - return true - } - return false + return DescriptorUtils.isCompanionObject(possibleCompanionObject) && + !DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration) } fun isJvmStaticProperty() = diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/reflectLambda.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/reflectLambda.kt index 7b3d9cc21f0..69659b14bb4 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/reflectLambda.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/reflectLambda.kt @@ -18,10 +18,13 @@ package kotlin.reflect.jvm +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.load.kotlin.JvmNameResolver +import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer +import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfoTable import org.jetbrains.kotlin.serialization.jvm.BitEncoding @@ -44,12 +47,32 @@ fun Function.reflect(): KFunction? { val stringTableTypes = JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY) val nameResolver = JvmNameResolver(stringTableTypes, annotation.d2) val proto = ProtoBuf.Function.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY) - val moduleData = javaClass.getOrCreateModule() - val context = DeserializationContext( - moduleData.deserialization, nameResolver, moduleData.module, TypeTable(proto.typeTable), SinceKotlinInfoTable.EMPTY, - containerSource = null, parentTypeDeserializer = null, typeParameters = proto.typeParameterList - ) - val descriptor = MemberDeserializer(context).loadFunction(proto) + + val descriptor = deserializeToDescriptor(javaClass, proto, nameResolver, TypeTable(proto.typeTable), MemberDeserializer::loadFunction) + ?: return null + @Suppress("UNCHECKED_CAST") return KFunctionImpl(EmptyContainerForLocal, descriptor) as KFunction } + +internal fun deserializeToDescriptor( + moduleAnchor: Class<*>, + proto: M, + nameResolver: NameResolver, + typeTable: TypeTable, + createDescriptor: MemberDeserializer.(M) -> D +): D? { + val moduleData = moduleAnchor.getOrCreateModule() + + val typeParameters = when (proto) { + is ProtoBuf.Function -> proto.typeParameterList + is ProtoBuf.Property -> proto.typeParameterList + else -> error("Unsupported message: $proto") + } + + val context = DeserializationContext( + moduleData.deserialization, nameResolver, moduleData.module, typeTable, SinceKotlinInfoTable.EMPTY, + containerSource = null, parentTypeDeserializer = null, typeParameters = typeParameters + ) + return MemberDeserializer(context).createDescriptor(proto) +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index fb36782726e..535d9c9a926 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -19545,6 +19545,15 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } } + + @TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalDelegated extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInLocalDelegated() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + } } @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns")