From 4d2fbf1801f4c9d5e814643e03eb31cb52ef1e07 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 17 Aug 2017 12:29:16 +0300 Subject: [PATCH] Fix reflection for local delegated properties inside interface #KT-19690 --- .../serialization/JvmSerializerExtension.java | 5 +++- .../properties/localDelegated/defaultImpls.kt | 23 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++++ .../LightAnalysisModeTestGenerated.java | 6 +++++ .../kotlin/reflect/jvm/internal/KClassImpl.kt | 9 ++++++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt 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 e6e71dd7d27..f844c9498d9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.java @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.protobuf.GeneratedMessageLite; import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.serialization.*; import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite; import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf; @@ -85,7 +86,9 @@ public class JvmSerializerExtension extends SerializerExtension { proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName)); } - writeLocalProperties(proto, typeMapper.mapClass(descriptor), JvmProtoBuf.classLocalVariable); + Type containerAsmType = + DescriptorUtils.isInterface(descriptor) ? typeMapper.mapDefaultImpls(descriptor) : typeMapper.mapClass(descriptor); + writeLocalProperties(proto, containerAsmType, JvmProtoBuf.classLocalVariable); } @Override diff --git a/compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt b/compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt new file mode 100644 index 00000000000..421e7402f1b --- /dev/null +++ b/compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt @@ -0,0 +1,23 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT + +import kotlin.reflect.KProperty +import kotlin.test.assertEquals + +object Delegate { + operator fun getValue(z: Any?, p: KProperty<*>): String? { + assertEquals("val x: kotlin.String?", p.toString()) + return "OK" + } +} + +interface Foo { + fun bar(): String { + val x by Delegate + return x!! + } +} + +object O : Foo + +fun box(): String = O.bar() 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 d5e719538be..723646df55c 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 @@ -16281,6 +16281,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("defaultImpls.kt") + public void testDefaultImpls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt"); + doTest(fileName); + } + @TestMetadata("inlineFun.kt") public void testInlineFun() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index bc760dde607..7f38b7b8e9c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16281,6 +16281,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("defaultImpls.kt") + public void testDefaultImpls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt"); + doTest(fileName); + } + @TestMetadata("inlineFun.kt") public void testInlineFun() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 66be4df359d..b927def74d0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16281,6 +16281,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("defaultImpls.kt") + public void testDefaultImpls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/defaultImpls.kt"); + doTest(fileName); + } + @TestMetadata("inlineFun.kt") public void testInlineFun() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt"); 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 0b997cfcfb2..675855237e9 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -199,6 +199,15 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration staticScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) override fun getLocalProperty(index: Int): PropertyDescriptor? { + // TODO: also check that this is a synthetic class (Metadata.k == 3) + if (jClass.simpleName == JvmAbi.DEFAULT_IMPLS_CLASS_NAME) { + jClass.declaringClass?.let { interfaceClass -> + if (interfaceClass.isInterface) { + return (interfaceClass.kotlin as KClassImpl<*>).getLocalProperty(index) + } + } + } + return (descriptor as? DeserializedClassDescriptor)?.let { descriptor -> val proto = descriptor.classProto.getExtension(JvmProtoBuf.classLocalVariable, index) val nameResolver = descriptor.c.nameResolver