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:
@@ -373,8 +373,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
if (generateBody) {
|
if (generateBody) {
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
Method method = typeMapper.mapAsmMethod(descriptor.getOriginal());
|
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, descriptor, state);
|
||||||
iv.aconst(method.getName() + method.getDescriptor());
|
|
||||||
iv.areturn(JAVA_STRING_TYPE);
|
iv.areturn(JAVA_STRING_TYPE);
|
||||||
FunctionCodegen.endVisit(iv, "function reference getSignature", element);
|
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)
|
// TODO: generate the container once and save to a local field instead (KT-10495)
|
||||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
|
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
|
||||||
iv.aconst(property.getName().asString());
|
iv.aconst(property.getName().asString());
|
||||||
iv.aconst(PropertyReferenceCodegen.getPropertyReferenceSignature(property, state));
|
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, property, state);
|
||||||
iv.invokespecial(
|
iv.invokespecial(
|
||||||
implType.getInternalName(), "<init>",
|
implType.getInternalName(), "<init>",
|
||||||
Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false
|
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.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||||
@@ -110,7 +111,7 @@ class PropertyReferenceCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||||
aconst(getPropertyReferenceSignature(target as VariableDescriptorWithAccessors, state))
|
generateCallableReferenceSignature(this, target, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLocalDelegatedProperty) {
|
if (!isLocalDelegatedProperty) {
|
||||||
@@ -180,14 +181,19 @@ class PropertyReferenceCodegen(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getPropertyReferenceSignature(property: VariableDescriptorWithAccessors, state: GenerationState): String {
|
fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
|
||||||
val getter =
|
val accessor = when (callable) {
|
||||||
property.getter ?: DescriptorFactory.createDefaultGetter(property as PropertyDescriptor, Annotations.EMPTY).apply {
|
is FunctionDescriptor -> callable
|
||||||
initialize(property.type)
|
is VariableDescriptorWithAccessors ->
|
||||||
|
callable.getter ?:
|
||||||
|
DescriptorFactory.createDefaultGetter(callable as PropertyDescriptor, Annotations.EMPTY).apply {
|
||||||
|
initialize(callable.type)
|
||||||
}
|
}
|
||||||
|
else -> error("Unsupported callable reference: $callable")
|
||||||
val method = state.typeMapper.mapAsmMethod(getter.original)
|
}
|
||||||
return method.name + method.descriptor
|
val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original
|
||||||
|
val method = state.typeMapper.mapAsmMethod(declaration)
|
||||||
|
iv.aconst(method.name + method.descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
+16
@@ -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"
|
||||||
|
}
|
||||||
+17
@@ -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);
|
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")
|
@TestMetadata("javaClassGetFunctions.kt")
|
||||||
public void testJavaClassGetFunctions() throws Exception {
|
public void testJavaClassGetFunctions() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/javaClassGetFunctions.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/javaClassGetFunctions.kt");
|
||||||
@@ -12999,6 +13005,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("genericProperty.kt")
|
||||||
public void testGenericProperty() throws Exception {
|
public void testGenericProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/genericProperty.kt");
|
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.constants.StringValue;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
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 org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||||
|
|
||||||
import java.util.*;
|
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
|
* 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.
|
* of the fake override in the supertypes, this method finds just only one of them.
|
||||||
* TODO: probably all call-sites of this method are wrong, they should handle all super-declarations
|
* TODO: probably some call-sites of this method are wrong, they should handle all super-declarations
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
Reference in New Issue
Block a user