Support reflection for local delegated properties

#KT-15222 Fixed
This commit is contained in:
Alexander Udalov
2017-06-01 19:42:59 +03:00
parent c444c4d10b
commit 616d575fb6
27 changed files with 559 additions and 48 deletions
@@ -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<ProtoBufPackageKind> {
@@ -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<ProtoBufClassKind> {
@@ -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
}
@@ -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;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension<
org.jetbrains.kotlin.serialization.DebugProtoBuf.Class,
java.util.List<org.jetbrains.kotlin.serialization.DebugProtoBuf.Property>> 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;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
@@ -4597,6 +4610,17 @@ public final class DebugJvmProtoBuf {
.newFileScopedGeneratedExtension(
java.lang.Integer.class,
null);
public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension<
org.jetbrains.kotlin.serialization.DebugProtoBuf.Package,
java.util.List<org.jetbrains.kotlin.serialization.DebugProtoBuf.Property>> 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);
@@ -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
@@ -119,9 +119,11 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
}
}
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);
@@ -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 <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D): D {
@Suppress("UNCHECKED_CAST")
val builder = descriptor.newCopyBuilder() as CallableMemberDescriptor.CopyBuilder<D>
val typeParameters = ArrayList<TypeParameterDescriptor>(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)
}
@@ -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 <MessageType extends GeneratedMessageLite.ExtendableMessage<MessageType>,
BuilderType extends GeneratedMessageLite.ExtendableBuilder<MessageType, BuilderType>> void writeLocalProperties(
@NotNull BuilderType proto,
@NotNull Type classAsmType,
@NotNull GeneratedMessageLite.GeneratedExtension<MessageType, List<ProtoBuf.Property>> extension
) {
List<VariableDescriptorWithAccessors> 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,
@@ -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;
}
@@ -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<String?> {
property = kProperty
return emptyList()
}
operator fun setValue(instance: Any?, kProperty: KProperty<*>, value: List<String?>) {
throw AssertionError()
}
}
fun check(expectedName: String, p: KProperty0<*>): String? {
assertEquals(expectedName, p.name)
assertEquals(emptyList<KParameter>(), p.parameters)
assertEquals(emptyList<KTypeParameter>(), p.typeParameters)
assertEquals(null, p.visibility) // "local" visibility is not representable with reflection API
assertEquals("kotlin.collections.List<kotlin.String?>", 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<KParameter>(), p.getter.parameters)
assertEquals("kotlin.collections.List<kotlin.String?>", p.getter.returnType.toString())
// TODO: support annotations
assertEquals(emptyList<Annotation>(), 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<kotlin.String?>"), 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"
}
@@ -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<String?> {
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<kotlin.String?>", Delegate.property.toString())
return "OK"
}
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.*
class Delegate<out T>(val value: T) {
lateinit var property: KProperty<*>
operator fun getValue(instance: Any?, kProperty: KProperty<*>): T {
property = kProperty
return value
}
}
class A<X> {
inner class B<Y> {
fun <Z> foo() {
val delegate = Delegate<Map<Pair<X, Y>, Z>>(emptyMap())
val c: Map<Pair<X, Y>, Z> by delegate
c
assertEquals("kotlin.collections.Map<kotlin.Pair<X, Y>, Z>", delegate.property.returnType.toString())
}
}
}
fun box(): String {
A<String>().B<Int>().foo<Double>()
return "OK"
}
@@ -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")
@@ -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")
@@ -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")
@@ -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;
}
@@ -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()
@@ -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;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
org.jetbrains.kotlin.serialization.ProtoBuf.Class,
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> 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;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
@@ -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;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
org.jetbrains.kotlin.serialization.ProtoBuf.Package,
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> 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 {
}
@@ -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<D> setKind(@NotNull Kind kind);
@NotNull
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
@NotNull
CopyBuilder<D> setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter);
@@ -117,6 +117,7 @@ public interface FunctionDescriptor extends CallableMemberDescriptor {
CopyBuilder<D> setValueParameters(@NotNull List<ValueParameterDescriptor> parameters);
@NotNull
@Override
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
@NotNull
@@ -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<PropertyDescriptor> {
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<TypeParameterDescriptor> newTypeParameters = null;
@NotNull
@Override
@@ -290,6 +286,13 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
return this;
}
@NotNull
@Override
public CopyBuilder<PropertyDescriptor> setTypeParameters(@NotNull List<TypeParameterDescriptor> 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<TypeParameterDescriptor> originalTypeParameters = getTypeParameters();
List<TypeParameterDescriptor> originalTypeParameters =
copyConfiguration.newTypeParameters == null ? getTypeParameters() : copyConfiguration.newTypeParameters;
List<TypeParameterDescriptor> substitutedTypeParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(
originalTypeParameters, copyConfiguration.substitution, substitutedDescriptor, substitutedTypeParameters
@@ -36,6 +36,10 @@ internal object EmptyContainerForLocal : KDeclarationContainerImpl() {
override fun getFunctions(name: Name): Collection<FunctionDescriptor> = fail()
private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " +
"is not yet fully supported in Kotlin reflection")
}
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"
)
}
@@ -268,6 +268,11 @@ internal abstract class FunctionCaller<out M : Member?>(
}
}
object ThrowingCaller : FunctionCaller<Nothing?>(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?
@@ -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<T : Any>(override val jClass: Class<T>) : 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
@@ -45,6 +45,8 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
abstract fun getFunctions(name: Name): Collection<FunctionDescriptor>
abstract fun getLocalProperty(index: Int): PropertyDescriptor?
protected fun getMembers(scope: MemberScope, belonginess: MemberBelonginess): Collection<KCallableImpl<*>> {
val visitor = object : DeclarationDescriptorVisitorEmptyBodies<KCallableImpl<*>, 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 = "<v#(\\d+)>".toRegex()
}
}
@@ -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<KCallableImpl<*>> 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<FunctionDescriptor> =
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
@@ -178,12 +178,14 @@ internal abstract class KPropertyImpl<out R> 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() =
@@ -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 <R> Function<R>.reflect(): KFunction<R>? {
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<R>
}
internal fun <M : MessageLite, D : CallableDescriptor> 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)
}
@@ -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")