Fix reflective access on overridden generic property reference

Generation of callable reference's signature in codegen should use the same
mechanism for obtaining the signature as the runtime in RuntimeTypeMapper,
namely DescriptorUtils.unwrapFakeOverride(...).original

 #KT-13700 Fixed
This commit is contained in:
Alexander Udalov
2016-09-05 16:38:12 +03:00
parent 6845d0958a
commit 90eafe0d71
7 changed files with 67 additions and 14 deletions
@@ -373,8 +373,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
if (generateBody) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
Method method = typeMapper.mapAsmMethod(descriptor.getOriginal());
iv.aconst(method.getName() + method.getDescriptor());
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, descriptor, state);
iv.areturn(JAVA_STRING_TYPE);
FunctionCodegen.endVisit(iv, "function reference getSignature", element);
}
@@ -525,7 +525,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
// TODO: generate the container once and save to a local field instead (KT-10495)
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
iv.aconst(property.getName().asString());
iv.aconst(PropertyReferenceCodegen.getPropertyReferenceSignature(property, state));
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, property, state);
iv.invokespecial(
implType.getInternalName(), "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
@@ -110,7 +111,7 @@ class PropertyReferenceCodegen(
}
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
aconst(getPropertyReferenceSignature(target as VariableDescriptorWithAccessors, state))
generateCallableReferenceSignature(this, target, state)
}
if (!isLocalDelegatedProperty) {
@@ -180,14 +181,19 @@ class PropertyReferenceCodegen(
companion object {
@JvmStatic
fun getPropertyReferenceSignature(property: VariableDescriptorWithAccessors, state: GenerationState): String {
val getter =
property.getter ?: DescriptorFactory.createDefaultGetter(property as PropertyDescriptor, Annotations.EMPTY).apply {
initialize(property.type)
fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
val accessor = when (callable) {
is FunctionDescriptor -> callable
is VariableDescriptorWithAccessors ->
callable.getter ?:
DescriptorFactory.createDefaultGetter(callable as PropertyDescriptor, Annotations.EMPTY).apply {
initialize(callable.type)
}
val method = state.typeMapper.mapAsmMethod(getter.original)
return method.name + method.descriptor
else -> error("Unsupported callable reference: $callable")
}
val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original
val method = state.typeMapper.mapAsmMethod(declaration)
iv.aconst(method.name + method.descriptor)
}
@JvmStatic
@@ -0,0 +1,16 @@
// WITH_REFLECT
import kotlin.test.assertEquals
interface H<T> {
fun foo(): T?
}
interface A : H<A>
fun box(): String {
assertEquals("A?", A::foo.returnType.toString())
assertEquals("T?", H<A>::foo.returnType.toString())
return "OK"
}
@@ -0,0 +1,17 @@
// WITH_REFLECT
// KT-13700 Exception obtaining descriptor for property reference
import kotlin.test.assertEquals
interface H<T> {
val parent : T?
}
interface A : H<A>
fun box(): String {
assertEquals("A?", A::parent.returnType.toString())
assertEquals("T?", H<A>::parent.returnType.toString())
return "OK"
}
@@ -12258,6 +12258,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("genericOverriddenFunction.kt")
public void testGenericOverriddenFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/genericOverriddenFunction.kt");
doTest(fileName);
}
@TestMetadata("javaClassGetFunctions.kt")
public void testJavaClassGetFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/javaClassGetFunctions.kt");
@@ -12999,6 +13005,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("genericOverriddenProperty.kt")
public void testGenericOverriddenProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/genericOverriddenProperty.kt");
doTest(fileName);
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/genericProperty.kt");
@@ -33,7 +33,10 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.StringValue;
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeConstructor;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import java.util.*;
@@ -418,8 +421,8 @@ public class DescriptorUtils {
/**
* Given a fake override, finds any declaration of it in the overridden descriptors. Keep in mind that there may be many declarations
* of the fake override in the supertypes, this method finds just the only one.
* TODO: probably all call-sites of this method are wrong, they should handle all super-declarations
* of the fake override in the supertypes, this method finds just only one of them.
* TODO: probably some call-sites of this method are wrong, they should handle all super-declarations
*/
@NotNull
@SuppressWarnings("unchecked")