Support references to extension properties in JVM codegen

#KT-1183 In Progress
This commit is contained in:
Alexander Udalov
2014-05-27 21:28:06 +04:00
parent 461cce103b
commit 5ab83aad8a
12 changed files with 140 additions and 16 deletions
@@ -785,4 +785,12 @@ public class AsmUtil {
return PackagePartClassUtils.getPackagePartInternalName(containingFile);
}
public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
if (isPrimitive(type)) {
v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
}
else {
v.aconst(type);
}
}
}
@@ -2426,6 +2426,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (variableDescriptor != null) {
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
String reflectionFieldOwner;
Type propertyType;
Type ownerType;
@@ -2436,7 +2438,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
reflectionFieldOwner =
PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName());
propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE;
if (receiverParameter != null) {
propertyType = descriptor.isVar() ? K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE : K_EXTENSION_PROPERTY_IMPL_TYPE;
}
else {
propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE;
}
ownerType = K_PACKAGE_IMPL_TYPE;
reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME;
}
@@ -2455,8 +2463,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.visitLdcInsn(descriptor.getName().asString());
v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor());
v.invokespecial(propertyType.getInternalName(), "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType), false);
String constructorDesc;
if (receiverParameter != null) {
putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType, getType(Class.class));
}
else {
constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType);
}
v.invokespecial(propertyType.getInternalName(), "<init>", constructorDesc, false);
return StackValue.onStack(propertyType);
}
@@ -19,8 +19,6 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetCallExpression;
@@ -28,11 +26,12 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.jet.codegen.AsmUtil.putJavaLangClassInstance;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
public class JavaClassFunction extends IntrinsicMethod {
@@ -51,13 +50,7 @@ public class JavaClassFunction extends IntrinsicMethod {
assert resolvedCall != null;
JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
assert returnType != null;
Type type = codegen.getState().getTypeMapper().mapType(returnType.getArguments().get(0).getType());
if (isPrimitive(type)) {
v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
}
else {
v.aconst(type);
}
putJavaLangClassInstance(v, codegen.getState().getTypeMapper().mapType(returnType.getArguments().get(0).getType()));
return getType(Class.class);
}
@@ -44,6 +44,8 @@ public class AsmTypeConstants {
public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl");
public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl");
public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl");
public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl");
public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl");
public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef");
@@ -0,0 +1,12 @@
val String.id: String
get() = this
fun box(): String {
val pr = String::id
if (pr["123"] != "123") return "Fail value: ${pr["123"]}"
if (pr.name != "id") return "Fail name: ${pr.name}"
return pr.get("OK")
}
@@ -0,0 +1,18 @@
var storage = 0
var Int.foo: Int
get() {
return this + storage
}
set(value) {
storage = this + value
}
fun box(): String {
val pr = Int::foo
if (pr.get(42) != 42) return "Fail 1: ${pr[42]}"
pr.set(200, 39)
if (pr.get(-239) != 0) return "Fail 2: ${pr[-239]}"
if (storage != 239) return "Fail 3: $storage"
return "OK"
}
@@ -0,0 +1,6 @@
package a
public var topLevel: Int = 42
public val String.extension: Long
get() = length.toLong()
@@ -0,0 +1,14 @@
import a.*
fun main(args: Array<String>) {
val f = ::topLevel
val x1 = f.get()
if (x1 != 42) throw AssertionError("Fail x1: $x1")
f.set(239)
val x2 = f.get()
if (x2 != 239) throw AssertionError("Fail x2: $x2")
val g = String::extension
val y1 = g.get("abcde")
if (y1 != 5L) throw AssertionError("Fail y1: $y1")
}
@@ -464,6 +464,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt");
}
@TestMetadata("simpleMutableExtension.kt")
public void testSimpleMutableExtension() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableExtension.kt");
}
@TestMetadata("simpleMutableMember.kt")
public void testSimpleMutableMember() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt");
@@ -28,6 +28,7 @@ import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GenerationUtils;
import org.jetbrains.jet.codegen.InlineTestUtil;
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.jet.config.CompilerConfiguration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
@@ -108,7 +109,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit
private void invokeMain() throws Exception {
URLClassLoader classLoader = new URLClassLoader(
new URL[]{ aDir.toURI().toURL(), bDir.toURI().toURL() },
new URL[]{ aDir.toURI().toURL(), bDir.toURI().toURL(), ForTestCompileRuntime.runtimeJarForTests().toURI().toURL() },
AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader()
);
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
@@ -118,7 +119,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit
private void invokeBox() throws Exception {
URLClassLoader classLoader = new URLClassLoader(
new URL[]{ bDir.toURI().toURL(), aDir.toURI().toURL() },
new URL[]{ bDir.toURI().toURL(), aDir.toURI().toURL(), ForTestCompileRuntime.runtimeJarForTests().toURI().toURL() },
AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader()
);
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
@@ -106,6 +106,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
doTest("compiler/testData/compileKotlinAgainstKotlin/PlatformNames.A.kt");
}
@TestMetadata("PropertyReference.A.kt")
public void testPropertyReference() throws Exception {
doTest("compiler/testData/compileKotlinAgainstKotlin/PropertyReference.A.kt");
}
@TestMetadata("Simple.A.kt")
public void testSimple() throws Exception {
doTest("compiler/testData/compileKotlinAgainstKotlin/Simple.A.kt");
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.Method
open class KExtensionPropertyImpl<T, out R>(
name: String,
protected val owner: KPackageImpl,
protected val receiverClass: Class<T>
) : KExtensionProperty<T, R>, KPropertyImpl<R>(name) {
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
protected val getter: Method = owner.jClass.getMethod(getterName(name), receiverClass)
override fun get(receiver: T): R {
return getter(null, receiver) as R
}
}
class KMutableExtensionPropertyImpl<T, R>(
name: String,
owner: KPackageImpl,
receiverClass: Class<T>
) : KMutableExtensionProperty<T, R>, KExtensionPropertyImpl<T, R>(name, owner, receiverClass) {
private val setter = owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!)
override fun set(receiver: T, value: R) {
setter.invoke(null, receiver, value)
}
}