Support reflection for local delegated properties
#KT-15222 Fixed
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
+39
-5
@@ -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,
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+75
@@ -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"
|
||||
}
|
||||
+43
@@ -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"
|
||||
}
|
||||
Vendored
+31
@@ -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"
|
||||
}
|
||||
+27
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user