Support :: references to Java instance fields in codegen
#KT-1183 In Progress
This commit is contained in:
@@ -50,6 +50,7 @@ import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
|
|||||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
|
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
@@ -2461,7 +2462,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
v.anew(propertyType);
|
v.anew(propertyType);
|
||||||
v.dup();
|
v.dup();
|
||||||
v.visitLdcInsn(descriptor.getName().asString());
|
v.visitLdcInsn(descriptor.getName().asString());
|
||||||
v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor());
|
|
||||||
|
if (containingDeclaration instanceof JavaClassDescriptor) {
|
||||||
|
v.aconst(Type.getObjectType(reflectionFieldOwner));
|
||||||
|
v.invokestatic("kotlin/reflect/jvm/internal/InternalPackage", "foreignKotlinClass",
|
||||||
|
Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO: built-in classes
|
||||||
|
v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
String constructorDesc;
|
String constructorDesc;
|
||||||
if (receiverParameter != null) {
|
if (receiverParameter != null) {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
public class publicFinalField {
|
||||||
|
public final String field = "OK";
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fun box() = (publicFinalField::field).get(publicFinalField())
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
public class publicMutableField {
|
||||||
|
public int field = 239;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import publicMutableField as A
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
val f = A::field
|
||||||
|
if (f.get(a) != 239) return "Fail 1: ${f.get(a)}"
|
||||||
|
f[a] = 42
|
||||||
|
if (f.get(a) != 42) return "Fail 2: ${f.get(a)}"
|
||||||
|
if (f.get(a) != 42) return "Fail 2: ${f.get(a)}"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+10
@@ -86,6 +86,16 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
|
|||||||
doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/constructor.kt");
|
doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/constructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("publicFinalField.kt")
|
||||||
|
public void testPublicFinalField() throws Exception {
|
||||||
|
doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/publicFinalField.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("publicMutableField.kt")
|
||||||
|
public void testPublicMutableField() throws Exception {
|
||||||
|
doTestAgainstJava("compiler/testData/codegen/boxAgainstJava/callableReference/publicMutableField.kt");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxAgainstJava/constructor")
|
@TestMetadata("compiler/testData/codegen/boxAgainstJava/constructor")
|
||||||
|
|||||||
@@ -16,6 +16,21 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
enum class KClassOrigin {
|
||||||
|
BUILT_IN
|
||||||
|
KOTLIN
|
||||||
|
FOREIGN
|
||||||
|
}
|
||||||
|
|
||||||
class KClassImpl<out T>(
|
class KClassImpl<out T>(
|
||||||
val jClass: Class<T>
|
val jClass: Class<T>
|
||||||
) : KClass<T>
|
) : KClass<T> {
|
||||||
|
val origin: KClassOrigin =
|
||||||
|
if (K_OBJECT_CLASS.isAssignableFrom(jClass)) {
|
||||||
|
KClassOrigin.KOTLIN
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
KClassOrigin.FOREIGN
|
||||||
|
// TODO: built-in classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,17 +16,32 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
open class KMemberPropertyImpl<T, out R>(
|
open class KMemberPropertyImpl<T, out R>(
|
||||||
name: String,
|
name: String,
|
||||||
protected val owner: KClassImpl<T>
|
protected val owner: KClassImpl<T>
|
||||||
) : KMemberProperty<T, R>, KPropertyImpl<R>(name) {
|
) : KMemberProperty<T, R>, KPropertyImpl<R>(name) {
|
||||||
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
|
protected val field: Field? =
|
||||||
protected val getter: Method = owner.jClass.getMethod(getterName(name))
|
if (owner.origin == KClassOrigin.FOREIGN) {
|
||||||
|
owner.jClass.getField(name)
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
|
||||||
|
// TODO: extract, make lazy (weak?), use our descriptors knowledge
|
||||||
|
protected val getter: Method? =
|
||||||
|
if (owner.origin == KClassOrigin.KOTLIN) {
|
||||||
|
owner.jClass.getMethod(getterName(name))
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
|
||||||
|
// TODO: built-in classes
|
||||||
override fun get(receiver: T): R {
|
override fun get(receiver: T): R {
|
||||||
return getter(receiver) as R
|
if (getter != null) {
|
||||||
|
return getter!!(receiver) as R
|
||||||
|
}
|
||||||
|
return field!!.get(receiver) as R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,9 +49,17 @@ class KMutableMemberPropertyImpl<T, R>(
|
|||||||
name: String,
|
name: String,
|
||||||
owner: KClassImpl<T>
|
owner: KClassImpl<T>
|
||||||
) : KMutableMemberProperty<T, R>, KMemberPropertyImpl<T, R>(name, owner) {
|
) : KMutableMemberProperty<T, R>, KMemberPropertyImpl<T, R>(name, owner) {
|
||||||
private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!)
|
private val setter: Method? =
|
||||||
|
if (owner.origin == KClassOrigin.KOTLIN) {
|
||||||
|
owner.jClass.getMethod(setterName(name), getter!!.getReturnType()!!)
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
|
||||||
override fun set(receiver: T, value: R) {
|
override fun set(receiver: T, value: R) {
|
||||||
setter.invoke(receiver, value)
|
if (setter != null) {
|
||||||
|
setter!!(receiver, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field!!.set(receiver, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
// TODO: use stdlib?
|
// TODO: use stdlib?
|
||||||
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||||
private fun String.capitalizeWithJavaBeanConvention(): String {
|
private fun String.capitalizeWithJavaBeanConvention(): String {
|
||||||
@@ -32,13 +34,24 @@ private fun getterName(propertyName: String): String = "get" + propertyName.capi
|
|||||||
private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention()
|
private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention()
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: should use weak references
|
||||||
|
private val foreignKClasses: MutableMap<Class<*>, KClassImpl<*>> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
fun <T> foreignKotlinClass(jClass: Class<T>): KClassImpl<T> {
|
||||||
|
val cached = foreignKClasses[jClass] as? KClassImpl<T>
|
||||||
|
if (cached != null) return cached
|
||||||
|
val result = KClassImpl<T>(jClass)
|
||||||
|
foreignKClasses.put(jClass, result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject")
|
private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject")
|
||||||
|
|
||||||
// TODO
|
|
||||||
fun <T> kotlinClass(jClass: Class<T>): KClassImpl<T> {
|
fun <T> kotlinClass(jClass: Class<T>): KClassImpl<T> {
|
||||||
if (K_OBJECT_CLASS.isAssignableFrom(jClass)) {
|
if (K_OBJECT_CLASS.isAssignableFrom(jClass)) {
|
||||||
val field = jClass.getDeclaredField("\$kotlinClass")
|
val field = jClass.getDeclaredField("\$kotlinClass")
|
||||||
return field.get(null) as KClassImpl<T>
|
return field.get(null) as KClassImpl<T>
|
||||||
}
|
}
|
||||||
throw UnsupportedOperationException("Unsupported class: $jClass")
|
// TODO: built-in classes
|
||||||
|
return foreignKotlinClass(jClass)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user