Support references to extension properties in JVM codegen
#KT-1183 In Progress
This commit is contained in:
@@ -785,4 +785,12 @@ public class AsmUtil {
|
|||||||
return PackagePartClassUtils.getPackagePartInternalName(containingFile);
|
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) {
|
if (variableDescriptor != null) {
|
||||||
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
||||||
|
|
||||||
|
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
|
||||||
|
|
||||||
String reflectionFieldOwner;
|
String reflectionFieldOwner;
|
||||||
Type propertyType;
|
Type propertyType;
|
||||||
Type ownerType;
|
Type ownerType;
|
||||||
@@ -2436,7 +2438,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
reflectionFieldOwner =
|
reflectionFieldOwner =
|
||||||
PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName());
|
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;
|
ownerType = K_PACKAGE_IMPL_TYPE;
|
||||||
reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME;
|
reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME;
|
||||||
}
|
}
|
||||||
@@ -2455,8 +2463,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
v.visitLdcInsn(descriptor.getName().asString());
|
v.visitLdcInsn(descriptor.getName().asString());
|
||||||
v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor());
|
v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor());
|
||||||
|
|
||||||
v.invokespecial(propertyType.getInternalName(), "<init>",
|
String constructorDesc;
|
||||||
Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType), false);
|
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);
|
return StackValue.onStack(propertyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ package org.jetbrains.jet.codegen.intrinsics;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.ExpressionCodegen;
|
||||||
import org.jetbrains.jet.codegen.StackValue;
|
import org.jetbrains.jet.codegen.StackValue;
|
||||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
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.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
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 java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
|
import static org.jetbrains.jet.codegen.AsmUtil.putJavaLangClassInstance;
|
||||||
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
|
|
||||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
|
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
|
||||||
|
|
||||||
public class JavaClassFunction extends IntrinsicMethod {
|
public class JavaClassFunction extends IntrinsicMethod {
|
||||||
@@ -51,13 +50,7 @@ public class JavaClassFunction extends IntrinsicMethod {
|
|||||||
assert resolvedCall != null;
|
assert resolvedCall != null;
|
||||||
JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||||
assert returnType != null;
|
assert returnType != null;
|
||||||
Type type = codegen.getState().getTypeMapper().mapType(returnType.getArguments().get(0).getType());
|
putJavaLangClassInstance(v, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getType(Class.class);
|
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_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl");
|
||||||
public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl");
|
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_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");
|
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")
|
||||||
|
}
|
||||||
+18
@@ -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")
|
||||||
|
}
|
||||||
+5
@@ -464,6 +464,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt");
|
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")
|
@TestMetadata("simpleMutableMember.kt")
|
||||||
public void testSimpleMutableMember() throws Exception {
|
public void testSimpleMutableMember() throws Exception {
|
||||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt");
|
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt");
|
||||||
|
|||||||
+3
-2
@@ -28,6 +28,7 @@ import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
|
|||||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||||
import org.jetbrains.jet.codegen.GenerationUtils;
|
import org.jetbrains.jet.codegen.GenerationUtils;
|
||||||
import org.jetbrains.jet.codegen.InlineTestUtil;
|
import org.jetbrains.jet.codegen.InlineTestUtil;
|
||||||
|
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
|
||||||
import org.jetbrains.jet.config.CompilerConfiguration;
|
import org.jetbrains.jet.config.CompilerConfiguration;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||||
@@ -108,7 +109,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit
|
|||||||
|
|
||||||
private void invokeMain() throws Exception {
|
private void invokeMain() throws Exception {
|
||||||
URLClassLoader classLoader = new URLClassLoader(
|
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()
|
AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader()
|
||||||
);
|
);
|
||||||
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
|
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
|
||||||
@@ -118,7 +119,7 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends TestCaseWit
|
|||||||
|
|
||||||
private void invokeBox() throws Exception {
|
private void invokeBox() throws Exception {
|
||||||
URLClassLoader classLoader = new URLClassLoader(
|
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()
|
AbstractCompileKotlinAgainstKotlinTest.class.getClassLoader()
|
||||||
);
|
);
|
||||||
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
|
Class<?> clazz = classLoader.loadClass(PackageClassUtils.getPackageClassName(FqName.ROOT));
|
||||||
|
|||||||
+5
@@ -106,6 +106,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
|||||||
doTest("compiler/testData/compileKotlinAgainstKotlin/PlatformNames.A.kt");
|
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")
|
@TestMetadata("Simple.A.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
doTest("compiler/testData/compileKotlinAgainstKotlin/Simple.A.kt");
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user