From 048a9b686e51c3265d3b3b6d221840ab715c3347 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 30 Jun 2015 16:07:51 +0300 Subject: [PATCH] Generate separate anonymous class for each property reference Each property reference obtained by the '::' operator now causes back-end to generate an anonymous subclass of the corresponding KProperty class, with the customized behavior. This fixes a number of issues: - get/set/name of property references now works without kotlin-reflect.jar in the classpath - get/set/name methods are now overridden with statically-generated property access instead of the default KPropertyImpl's behavior of using Java reflection, which should be a lot faster - references to private/protected properties now work without the need to set 'accessible' flag, because corresponding synthetic accessors are generated at compile-time near the target property #KT-6870 Fixed #KT-6873 Fixed #KT-7033 Fixed --- .../kotlin/codegen/ClosureCodegen.java | 31 +-- .../kotlin/codegen/ExpressionCodegen.java | 109 +++------- .../kotlin/codegen/JvmRuntimeTypes.java | 20 +- .../kotlin/codegen/MemberCodegen.java | 12 ++ .../codegen/PropertyReferenceCodegen.kt | 201 ++++++++++++++++++ .../binding/CodegenAnnotatingVisitor.java | 42 ++-- .../codegen/binding/CodegenBinding.java | 33 +-- .../codegen/context/ClosureContext.java | 4 +- .../kotlin/codegen/context/LocalLookup.java | 2 +- .../codegen/inline/InlineCodegenUtil.java | 2 +- .../kotlin/codegen/inline/LambdaInfo.java | 2 +- .../kotlin/resolve/jvm/AsmTypes.java | 4 + .../reflection/mapping/javaFields.kt | 4 +- .../kt6870_privatePropertyReference.kt | 22 ++ .../properties}/privateClassVal.kt | 2 +- .../properties}/privateClassVar.kt | 2 +- .../properties}/protectedClassVar.kt | 3 +- ...lackBoxWithStdlibCodegenTestGenerated.java | 42 ++-- .../jvm/internal/DescriptorBasedProperty.kt | 10 +- .../jvm/internal/KCallableContainerImpl.kt | 10 +- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 6 - .../reflect/jvm/internal/KPackageImpl.kt | 12 -- .../reflect/jvm/internal/KProperty0Impl.kt | 38 +++- .../reflect/jvm/internal/KProperty1Impl.kt | 42 +++- .../reflect/jvm/internal/KProperty2Impl.kt | 4 +- .../jvm/internal/ReflectionFactoryImpl.java | 29 +-- .../reflect/jvm/internal/RuntimeTypeMapper.kt | 88 ++++---- .../src/kotlin/reflect/jvm/mapping.kt | 17 +- .../jvm/internal/CallableReference.java | 68 ++++++ .../jvm/internal/FunctionReference.java | 13 +- .../internal/MutablePropertyReference.java | 22 ++ .../internal/MutablePropertyReference0.java | 31 +++ .../internal/MutablePropertyReference1.java | 31 +++ .../internal/MutablePropertyReference2.java | 31 +++ .../jvm/internal/PropertyReference.java | 22 ++ .../jvm/internal/PropertyReference0.java | 26 +++ .../jvm/internal/PropertyReference1.java | 26 +++ .../jvm/internal/PropertyReference2.java | 26 +++ .../src/kotlin/jvm/internal/Reflection.java | 24 +-- .../jvm/internal/ReflectionFactory.java | 24 +-- 40 files changed, 833 insertions(+), 304 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt rename compiler/testData/codegen/boxWithStdlib/{callableReference/property => reflection/properties}/privateClassVal.kt (88%) rename compiler/testData/codegen/boxWithStdlib/{callableReference/property => reflection/properties}/privateClassVar.kt (89%) rename compiler/testData/codegen/boxWithStdlib/{callableReference/property => reflection/properties}/protectedClassVar.kt (84%) create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index b9f6c7a80d9..e8c1415888d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -202,7 +202,7 @@ public class ClosureCodegen extends MemberCodegen { this.constructor = generateConstructor(); if (isConst(closure)) { - generateConstInstance(); + generateConstInstance(asmType); } genClosureFields(closure, v, typeMapper); @@ -251,30 +251,12 @@ public class ClosureCodegen extends MemberCodegen { ); } - private void generateConstInstance() { - MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "", "()V", null, - ArrayUtil.EMPTY_STRING_ARRAY); - InstructionAdapter iv = new InstructionAdapter(mv); - - v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), - null, null); - - if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitCode(); - iv.anew(asmType); - iv.dup(); - iv.invokespecial(asmType.getInternalName(), "", "()V", false); - iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); - mv.visitInsn(RETURN); - FunctionCodegen.endVisit(mv, "", element); - } - } - private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) { if (bridge.equals(delegate)) return; MethodVisitor mv = - v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); + v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, + bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; @@ -306,6 +288,7 @@ public class ClosureCodegen extends MemberCodegen { FunctionCodegen.endVisit(mv, "bridge", element); } + // TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction? private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) { int flags = ACC_PUBLIC | ACC_FINAL; boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL; @@ -316,7 +299,7 @@ public class ClosureCodegen extends MemberCodegen { if (generateBody) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); - generateFunctionReferenceDeclarationContainer(iv, descriptor, typeMapper); + generateCallableReferenceDeclarationContainer(iv, descriptor, typeMapper); iv.areturn(K_DECLARATION_CONTAINER_TYPE); FunctionCodegen.endVisit(iv, "function reference getOwner", element); } @@ -347,9 +330,9 @@ public class ClosureCodegen extends MemberCodegen { } } - private static void generateFunctionReferenceDeclarationContainer( + public static void generateCallableReferenceDeclarationContainer( @NotNull InstructionAdapter iv, - @NotNull FunctionDescriptor descriptor, + @NotNull CallableDescriptor descriptor, @NotNull JetTypeMapper typeMapper ) { DeclarationDescriptor container = descriptor.getContainingDeclaration(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 591f878d981..4efc5b90c7e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; +import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; @@ -51,7 +52,6 @@ import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor; -import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; @@ -85,7 +85,6 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; -import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; @@ -2755,29 +2754,39 @@ public class ExpressionCodegen extends JetVisitor implem (FunctionDescriptor) resolvedCall.getResultingDescriptor()); } - VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); - if (variableDescriptor == null) { - throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); - } - // TODO: this diagnostic should also be reported on function references once they obtain reflection checkReflectionIsAvailable(expression); - VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); + VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); + if (variableDescriptor != null) { + return generatePropertyReference(expression, variableDescriptor, resolvedCall); + } - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - if (containingDeclaration instanceof PackageFragmentDescriptor) { - return generateTopLevelPropertyReference(descriptor); - } - else if (containingDeclaration instanceof ClassDescriptor) { - return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration); - } - else if (containingDeclaration instanceof ScriptDescriptor) { - return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor()); - } - else { - throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); - } + throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); + } + + @NotNull + private StackValue generatePropertyReference( + @NotNull JetCallableReferenceExpression expression, + @NotNull VariableDescriptor variableDescriptor, + @NotNull ResolvedCall resolvedCall + ) { + ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor); + + ClassBuilder classBuilder = state.getFactory().newVisitor( + OtherOrigin(expression), + typeMapper.mapClass(classDescriptor), + expression.getContainingFile() + ); + + @SuppressWarnings("unchecked") + PropertyReferenceCodegen codegen = new PropertyReferenceCodegen( + state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION), + expression, classBuilder, classDescriptor, (ResolvedCall) resolvedCall + ); + codegen.generate(); + + return codegen.putInstanceOnStack(); } private void checkReflectionIsAvailable(@NotNull JetExpression expression) { @@ -2786,64 +2795,6 @@ public class ExpressionCodegen extends JetVisitor implem } } - @NotNull - private StackValue generateTopLevelPropertyReference(@NotNull final VariableDescriptor descriptor) { - PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration(); - final String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName()); - - final ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); - final Method factoryMethod; - if (receiverParameter != null) { - Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE, getType(Class.class)}; - factoryMethod = descriptor.isVar() - ? method("mutableTopLevelExtensionProperty", K_MUTABLE_PROPERTY1_TYPE, parameterTypes) - : method("topLevelExtensionProperty", K_PROPERTY1_TYPE, parameterTypes); - } - else { - Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE}; - factoryMethod = descriptor.isVar() - ? method("mutableTopLevelVariable", K_MUTABLE_PROPERTY0_TYPE, parameterTypes) - : method("topLevelVariable", K_PROPERTY0_TYPE, parameterTypes); - } - - return StackValue.operation(factoryMethod.getReturnType(), new Function1() { - @Override - public Unit invoke(InstructionAdapter v) { - v.visitLdcInsn(descriptor.getName().asString()); - v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor()); - - if (receiverParameter != null) { - putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); - } - - v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false); - return Unit.INSTANCE$; - } - }); - } - - @NotNull - private StackValue generateMemberPropertyReference( - @NotNull final VariableDescriptor descriptor, - @NotNull final ClassDescriptor containingClass - ) { - final Method factoryMethod = descriptor.isVar() - ? method("mutableMemberProperty", K_MUTABLE_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE) - : method("memberProperty", K_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE); - - return StackValue.operation(factoryMethod.getReturnType(), new Function1() { - @Override - public Unit invoke(InstructionAdapter v) { - v.visitLdcInsn(descriptor.getName().asString()); - StackValue receiverClass = generateClassLiteralReference(typeMapper, containingClass.getDefaultType()); - receiverClass.put(receiverClass.type, v); - v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false); - - return Unit.INSTANCE$; - } - }); - } - @NotNull public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final JetType type) { return StackValue.operation(K_CLASS_TYPE, new Function1() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java index 5db8904a904..492048c5675 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java @@ -29,15 +29,15 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; +import java.util.*; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns; public class JvmRuntimeTypes { private final ClassDescriptor lambda; private final ClassDescriptor functionReference; + private final List propertyReferences; + private final List mutablePropertyReferences; public JvmRuntimeTypes() { ModuleDescriptorImpl module = new ModuleDescriptorImpl( @@ -49,6 +49,13 @@ public class JvmRuntimeTypes { this.lambda = createClass(kotlinJvmInternal, "Lambda"); this.functionReference = createClass(kotlinJvmInternal, "FunctionReference"); + this.propertyReferences = new ArrayList(3); + this.mutablePropertyReferences = new ArrayList(3); + + for (int i = 0; i <= 2; i++) { + propertyReferences.add(createClass(kotlinJvmInternal, "PropertyReference" + i)); + mutablePropertyReferences.add(createClass(kotlinJvmInternal, "MutablePropertyReference" + i)); + } } @NotNull @@ -98,4 +105,11 @@ public class JvmRuntimeTypes { return Arrays.asList(functionReference.getDefaultType(), functionType); } + + @NotNull + public JetType getSupertypeForPropertyReference(@NotNull PropertyDescriptor descriptor) { + int arity = (descriptor.getExtensionReceiverParameter() != null ? 1 : 0) + + (descriptor.getDispatchReceiverParameter() != null ? 1 : 0); + return (descriptor.isVar() ? mutablePropertyReferences : propertyReferences).get(arity).getDefaultType(); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 6e0108e2d50..97724959a7b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -532,4 +532,16 @@ public abstract class MemberCodegen", "()V", false); + iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); + } + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt new file mode 100644 index 00000000000..c7918316638 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2010-2015 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 org.jetbrains.kotlin.codegen + +import org.jetbrains.kotlin.codegen.AsmUtil.method +import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation +import org.jetbrains.kotlin.codegen.context.ClassContext +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.JetCallableReferenceExpression +import org.jetbrains.kotlin.resolve.DescriptorFactory +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver +import org.jetbrains.kotlin.utils.sure +import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL +import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC +import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SUPER +import org.jetbrains.org.objectweb.asm.Opcodes.V1_6 +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.commons.Method + +public class PropertyReferenceCodegen( + state: GenerationState, + parentCodegen: MemberCodegen<*>, + context: ClassContext, + expression: JetCallableReferenceExpression, + classBuilder: ClassBuilder, + private val classDescriptor: ClassDescriptor, + private val resolvedCall: ResolvedCall +) : MemberCodegen(state, parentCodegen, context, expression, classBuilder) { + private val target = resolvedCall.getResultingDescriptor() + private val asmType = typeMapper.mapClass(classDescriptor) + private val superAsmType: Type + + init { + val superClass = classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" } + superAsmType = typeMapper.mapClass(superClass) + } + + override fun generateDeclaration() { + v.defineClass( + element, + V1_6, + ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor), // TODO: test inline + asmType.getInternalName(), + null, + superAsmType.getInternalName(), + emptyArray() + ) + + v.visitSource(element.getContainingFile().getName(), null) + } + + // TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction? + override fun generateBody() { + // TODO: instance should be already wrapped by Reflection + generateConstInstance(asmType) + + generateMethod("property reference init", 0, method("", Type.VOID_TYPE)) { + load(0, OBJECT_TYPE) + invokespecial(superAsmType.getInternalName(), "", "()V", false) + } + + generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) { + ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, typeMapper) + } + + generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) { + aconst(target.getName().asString()) + } + + generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) { + target as PropertyDescriptor + + val getter = target.getGetter() ?: run { + val defaultGetter = DescriptorFactory.createDefaultGetter(target) + defaultGetter.initialize(target.getType()) + defaultGetter + } + + val method = typeMapper.mapSignature(getter.sure { "No getter: $target" }).getAsmMethod() + aconst(method.getName() + method.getDescriptor()) + } + + generateAccessors() + } + + private fun generateAccessors() { + val dispatchReceiver = resolvedCall.getDispatchReceiver() + val extensionReceiver = resolvedCall.getExtensionReceiver() + val receiverType = + when { + dispatchReceiver is ScriptReceiver -> { + // TODO: fix receiver for scripts, see ScriptReceiver#getType + dispatchReceiver.getDeclarationDescriptor().getClassDescriptor().getDefaultType() + } + dispatchReceiver.exists() -> dispatchReceiver.getType() + extensionReceiver.exists() -> extensionReceiver.getType() + else -> null + } + + fun generateAccessor(method: Method, accessorBody: InstructionAdapter.(StackValue) -> Unit) { + generateMethod("property reference $method", ACC_PUBLIC, method) { + // Note: this descriptor is an inaccurate representation of the get/set method. In particular, it has incorrect + // return type and value parameter types. However, it's created only to be able to use + // ExpressionCodegen#intermediateValueForProperty, which is poorly coupled with everything else. + val fakeDescriptor = SimpleFunctionDescriptorImpl.create( + classDescriptor, Annotations.EMPTY, Name.identifier(method.getName()), CallableMemberDescriptor.Kind.DECLARATION, + SourceElement.NO_SOURCE + ) + fakeDescriptor.initialize(null, classDescriptor.getThisAsReceiverParameter(), emptyList(), emptyList(), + classDescriptor.builtIns.getAnyType(), Modality.OPEN, Visibilities.PUBLIC) + + val fakeCodegen = ExpressionCodegen( + this, FrameMap(), OBJECT_TYPE, context.intoFunction(fakeDescriptor), state, this@PropertyReferenceCodegen + ) + + val receiver = + if (receiverType != null) StackValue.coercion(StackValue.local(1, OBJECT_TYPE), typeMapper.mapType(receiverType)) + else StackValue.none() + val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, receiver) + + accessorBody(value) + } + } + + val getterParameters = if (receiverType != null) arrayOf(OBJECT_TYPE) else emptyArray() + generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value -> + value.put(OBJECT_TYPE, this) + } + + if (!target.isVar()) return + + val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE)).toTypedArray() + generateAccessor(method("set", Type.VOID_TYPE, *setterParameters)) { value -> + // Hard-coded 1 or 2 is safe here because there's only java/lang/Object in the signature, no double/long parameters + value.store(StackValue.local(if (receiverType != null) 2 else 1, OBJECT_TYPE), this) + } + } + + private fun generateMethod(debugString: String, access: Int, method: Method, generate: InstructionAdapter.() -> Unit) { + val mv = v.newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, method.getName(), method.getDescriptor(), null, null) + + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + val iv = InstructionAdapter(mv) + iv.visitCode() + iv.generate() + iv.areturn(method.getReturnType()) + FunctionCodegen.endVisit(mv, debugString, element) + } + } + + override fun generateKotlinAnnotation() { + writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER) + } + + public fun putInstanceOnStack(): StackValue { + val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null + + val method = + when { + hasReceiver -> when { + target.isVar() -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1) + else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1) + } + else -> when { + target.isVar() -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0) + else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0) + } + } + + return StackValue.operation(method.getReturnType()) { iv -> + iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()) + iv.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false) + } + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index c93832eaec0..69855dca290 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -84,15 +84,15 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { } @NotNull - private ClassDescriptor recordClassForFunction( + private ClassDescriptor recordClassForCallable( @NotNull JetElement element, - @NotNull FunctionDescriptor funDescriptor, + @NotNull CallableDescriptor callableDescriptor, @NotNull Collection supertypes, @NotNull String name ) { String simpleName = name.substring(name.lastIndexOf('/') + 1); ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl( - correctContainerForLambda(funDescriptor, element), + correctContainerForLambda(callableDescriptor, element), Name.special(""), Modality.FINAL, supertypes, @@ -100,13 +100,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { ); classDescriptor.initialize(JetScope.Empty.INSTANCE$, Collections.emptySet(), null); - bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor); + bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor); return classDescriptor; } @NotNull @SuppressWarnings("ConstantConditions") - private DeclarationDescriptor correctContainerForLambda(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) { + private DeclarationDescriptor correctContainerForLambda(@NotNull CallableDescriptor descriptor, @NotNull JetElement function) { DeclarationDescriptor container = descriptor.getContainingDeclaration(); // In almost all cases the function's direct container is the correct container to consider in JVM back-end @@ -286,7 +286,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { String name = inventAnonymousClassName(expression); Collection supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor); - ClassDescriptor classDescriptor = recordClassForFunction(functionLiteral, functionDescriptor, supertypes, name); + ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name); recordClosure(classDescriptor, name); classStack.push(classDescriptor); @@ -298,17 +298,31 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { @Override public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) { - FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); - // working around a problem with shallow analysis - if (functionDescriptor == null) return; - ResolvedCall referencedFunction = CallUtilPackage.getResolvedCall(expression.getCallableReference(), bindingContext); if (referencedFunction == null) return; - Collection supertypes = - runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) referencedFunction.getResultingDescriptor()); + CallableDescriptor target = referencedFunction.getResultingDescriptor(); + + CallableDescriptor callableDescriptor; + Collection supertypes; + + if (target instanceof FunctionDescriptor) { + callableDescriptor = bindingContext.get(FUNCTION, expression); + if (callableDescriptor == null) return; + + supertypes = runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) target); + } + else if (target instanceof PropertyDescriptor) { + callableDescriptor = bindingContext.get(VARIABLE, expression); + if (callableDescriptor == null) return; + + supertypes = Collections.singleton(runtimeTypes.getSupertypeForPropertyReference((PropertyDescriptor) target)); + } + else { + return; + } String name = inventAnonymousClassName(expression); - ClassDescriptor classDescriptor = recordClassForFunction(expression, functionDescriptor, supertypes, name); + ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name); recordClosure(classDescriptor, name); classStack.push(classDescriptor); @@ -354,7 +368,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid { else { String name = inventAnonymousClassName(function); Collection supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor); - ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, supertypes, name); + ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name); recordClosure(classDescriptor, name); classStack.push(classDescriptor); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index e5e9355c4af..bfbcb51e979 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -40,16 +40,14 @@ import org.jetbrains.org.objectweb.asm.Type; import java.util.*; -import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface; import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; -import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall; import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement; public class CodegenBinding { public static final WritableSlice CLOSURE = Slices.createSimpleSlice(); - public static final WritableSlice CLASS_FOR_FUNCTION = Slices.createSimpleSlice(); + public static final WritableSlice CLASS_FOR_CALLABLE = Slices.createSimpleSlice(); public static final WritableSlice CLASS_FOR_SCRIPT = Slices.createSimpleSlice(); @@ -110,34 +108,41 @@ public class CodegenBinding { } @NotNull - public static ClassDescriptor anonymousClassForFunction( + public static ClassDescriptor anonymousClassForCallable( @NotNull BindingContext bindingContext, - @NotNull FunctionDescriptor descriptor + @NotNull CallableDescriptor descriptor ) { //noinspection ConstantConditions - return bindingContext.get(CLASS_FOR_FUNCTION, descriptor); + return bindingContext.get(CLASS_FOR_CALLABLE, descriptor); } @NotNull public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) { if (expression instanceof JetObjectLiteralExpression) { - JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression; - expression = jetObjectLiteralExpression.getObjectDeclaration(); + expression = ((JetObjectLiteralExpression) expression).getObjectDeclaration(); } ClassDescriptor descriptor = bindingContext.get(CLASS, expression); - if (descriptor == null) { - SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); - assert functionDescriptor != null : "Couldn't find function descriptor for " + PsiUtilPackage.getElementTextWithContext(expression); + if (descriptor != null) { + return getAsmType(bindingContext, descriptor); + } + + SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); + if (functionDescriptor != null) { return asmTypeForAnonymousClass(bindingContext, functionDescriptor); } - return getAsmType(bindingContext, descriptor); + VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); + if (variableDescriptor != null) { + return asmTypeForAnonymousClass(bindingContext, variableDescriptor); + } + + throw new IllegalStateException("Couldn't compute ASM type for " + PsiUtilPackage.getElementTextWithContext(expression)); } @NotNull - public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) { - return getAsmType(bindingContext, anonymousClassForFunction(bindingContext, descriptor)); + public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) { + return getAsmType(bindingContext, anonymousClassForCallable(bindingContext, descriptor)); } public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ClosureContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ClosureContext.java index 96a2f541028..e51bc7ced13 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ClosureContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ClosureContext.java @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.OwnerKind; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForFunction; +import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForCallable; public class ClosureContext extends ClassContext { private final FunctionDescriptor functionDescriptor; @@ -33,7 +33,7 @@ public class ClosureContext extends ClassContext { @Nullable CodegenContext parentContext, @NotNull LocalLookup localLookup ) { - super(typeMapper, anonymousClassForFunction(typeMapper.getBindingContext(), functionDescriptor), + super(typeMapper, anonymousClassForCallable(typeMapper.getBindingContext(), functionDescriptor), OwnerKind.IMPLEMENTATION, parentContext, localLookup); this.functionDescriptor = functionDescriptor; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java index 401a7314ebd..8f1413c69c4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java @@ -103,7 +103,7 @@ public interface LocalLookup { BindingContext bindingContext = state.getBindingContext(); Type localType = asmTypeForAnonymousClass(bindingContext, vd); - MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd)); + MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd)); if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) { // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance // (instead of passing this instance to the constructor and storing as a field) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index d5f142da4e1..d35b9448bca 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -234,7 +234,7 @@ public class InlineCodegenUtil { return type.getInternalName(); } else if (currentDescriptor instanceof FunctionDescriptor) { ClassDescriptor descriptor = - typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_FUNCTION, (FunctionDescriptor) currentDescriptor); + typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor); if (descriptor != null) { Type type = typeMapper.mapType(descriptor); return type.getInternalName(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java index e8e6656557c..c3782e78277 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java @@ -70,7 +70,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner { functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression); assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText(); - classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor); + classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor); closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor); closure = bindingContext.get(CLOSURE, classDescriptor); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 853ec58a853..ea288900c2c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -36,6 +36,10 @@ public class AsmTypes { public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda"); public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference"); + public static final Type PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/PropertyReference0"); + public static final Type PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/PropertyReference1"); + public static final Type MUTABLE_PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference0"); + public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1"); public static final Type K_CLASS_TYPE = reflect("KClass"); public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor()); diff --git a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt index 8d89bd89451..bd5f9a4fc71 100644 --- a/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt +++ b/compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt @@ -10,8 +10,8 @@ fun box(): String { val s = J::s // Check that correct reflection objects are created - assert(i.javaClass.getSimpleName() == "KProperty1Impl", "Fail i class") - assert(s.javaClass.getSimpleName() == "KMutableProperty1Impl", "Fail s class") + assert(i !is KMutableProperty<*>, "Fail i class: ${i.javaClass}") + assert(s is KMutableProperty<*>, "Fail s class: ${s.javaClass}") // Check that no Method objects are created for such properties assert(i.javaGetter == null, "Fail i getter") diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt new file mode 100644 index 00000000000..3bfa39df049 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt @@ -0,0 +1,22 @@ +class Test { + private var iv = 1 + + public fun exec() { + val t = object : Thread() { + override fun run() { + ::iv.get(this@Test) + ::iv.set(this@Test, 2) + } + } + t.start() + t.join(1000) + } + + fun result() = if (iv == 2) "OK" else "Fail $iv" +} + +fun box(): String { + val t = Test() + t.exec() + return t.result() +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt similarity index 88% rename from compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt index 99f6d3ee6d9..6a0d84da88d 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt @@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible class Result { private val value = "OK" - fun ref(): KProperty1 = ::value + fun ref() = Result::class.properties.single() as KProperty1 } fun box(): String { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt similarity index 89% rename from compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt index 0d5ea464a93..81f336e698f 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt @@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible class A { private var value = 0 - fun ref(): KMutableProperty1 = ::value + fun ref() = A::class.properties.single() as KMutableProperty1 } fun box(): String { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt similarity index 84% rename from compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt index 9263a9b188f..578b45f3e2e 100644 --- a/compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt @@ -1,10 +1,11 @@ import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.jvm.accessible +import kotlin.reflect.KMutableProperty1 class A(param: String) { protected var v: String = param - fun ref() = ::v + fun ref() = A::class.properties.single() as KMutableProperty1 } fun box(): String { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index a02c2e6c25e..561b9c1c6ea 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -795,6 +795,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("kt6870_privatePropertyReference.kt") + public void testKt6870_privatePropertyReference() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("localClassVar.kt") public void testLocalClassVar() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt"); @@ -813,24 +819,6 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } - @TestMetadata("privateClassVal.kt") - public void testPrivateClassVal() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt"); - doTestWithStdlib(fileName); - } - - @TestMetadata("privateClassVar.kt") - public void testPrivateClassVar() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt"); - doTestWithStdlib(fileName); - } - - @TestMetadata("protectedClassVar.kt") - public void testProtectedClassVar() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt"); - doTestWithStdlib(fileName); - } - @TestMetadata("publicClassValAccessible.kt") public void testPublicClassValAccessible() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt"); @@ -3222,6 +3210,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("privateClassVal.kt") + public void testPrivateClassVal() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("privateClassVar.kt") + public void testPrivateClassVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("privateFakeOverrideFromSuperclass.kt") public void testPrivateFakeOverrideFromSuperclass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateFakeOverrideFromSuperclass.kt"); @@ -3240,6 +3240,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("protectedClassVar.kt") + public void testProtectedClassVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("simpleGetProperties.kt") public void testSimpleGetProperties() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt index c281e039e43..a0646108cb5 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt @@ -30,17 +30,17 @@ import java.lang.reflect.Method abstract class DescriptorBasedProperty protected constructor( container: KCallableContainerImpl, name: String, - receiverParameterDesc: String?, + signature: String, descriptorInitialValue: PropertyDescriptor? ) { - constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : this( - container, name, receiverParameterClass?.desc, null + constructor(container: KCallableContainerImpl, name: String, signature: String) : this( + container, name, signature, null ) constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this( container, descriptor.getName().asString(), - descriptor.getExtensionReceiverParameter()?.getType()?.let { type -> RuntimeTypeMapper.mapTypeToJvmDesc(type) }, + RuntimeTypeMapper.mapPropertySignature(descriptor), descriptor ) @@ -51,7 +51,7 @@ abstract class DescriptorBasedProperty protected constructor( ) protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { - container.findPropertyDescriptor(name, receiverParameterDesc) + container.findPropertyDescriptor(name, signature) } // null if this is a property declared in a foreign (Java) class diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt index bedc410dd47..08141bae80b 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt @@ -43,20 +43,16 @@ abstract class KCallableContainerImpl : KDeclarationContainer { abstract val scope: JetScope - fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor { + fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor { val properties = scope .getProperties(Name.guess(name)) .filter { descriptor -> descriptor is PropertyDescriptor && - descriptor.getName().asString() == name && - with(descriptor.getExtensionReceiverParameter()) { - (this == null && receiverDesc == null) || - (this != null && RuntimeTypeMapper.mapTypeToJvmDesc(getType()) == receiverDesc) - } + RuntimeTypeMapper.mapPropertySignature(descriptor) == signature } if (properties.size() != 1) { - val debugText = if (receiverDesc == null) name else "'$receiverDesc.$name'" + val debugText = "'$name' (JVM signature: $signature)" throw KotlinReflectionInternalError( if (properties.isEmpty()) "Property $debugText not resolved in $this" else "${properties.size()} properties $debugText resolved in $this: $properties" diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 73c98ce0a1a..903648d59cf 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -104,12 +104,6 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K .map(create) .toList() - fun memberProperty(name: String): KProperty1 = - KProperty1Impl(this, name, null) - - fun mutableMemberProperty(name: String): KMutableProperty1 = - KMutableProperty1Impl(this, name, null) - override fun equals(other: Any?): Boolean = other is KClassImpl<*> && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 22c389274ab..22d236f0b45 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -31,18 +31,6 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP override val scope: JetScope get() = descriptor.memberScope - fun topLevelVariable(name: String): KProperty0<*> = - KProperty0Impl(this, name) - - fun mutableTopLevelVariable(name: String): KMutableProperty0<*> = - KMutableProperty0Impl(this, name) - - fun topLevelExtensionProperty(name: String, receiver: Class): KProperty1 = - KProperty1Impl(this, name, receiver) - - fun mutableTopLevelExtensionProperty(name: String, receiver: Class): KMutableProperty1 = - KMutableProperty1Impl(this, name, receiver) - override fun equals(other: Any?): Boolean = other is KPackageImpl && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt index 0fa44d92f64..fcbfd7c12aa 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -17,12 +17,14 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.Method +import kotlin.jvm.internal.MutablePropertyReference0 +import kotlin.jvm.internal.PropertyReference0 import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KProperty0 open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KPropertyImpl { - constructor(container: KPackageImpl, name: String) : super(container, name, null) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) override val name: String get() = descriptor.getName().asString() @@ -39,8 +41,8 @@ open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KProp } } -class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, KMutablePropertyImpl { - constructor(container: KPackageImpl, name: String) : super(container, name) +open class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, KMutablePropertyImpl { + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) override val setter: Method get() = super.setter!! @@ -53,3 +55,33 @@ class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, KMutab } } } + + +class KProperty0FromReferenceImpl( + val reference: PropertyReference0 +) : KProperty0Impl( + reference.getOwner() as KCallableContainerImpl, + reference.getName(), + reference.getSignature() +) { + override val name: String get() = reference.getName() + + override fun get(): Any? = reference.get() +} + + +class KMutableProperty0FromReferenceImpl( + val reference: MutablePropertyReference0 +) : KMutableProperty0Impl( + reference.getOwner() as KCallableContainerImpl, + reference.getName(), + reference.getSignature() +) { + override val name: String get() = reference.getName() + + override fun get(): Any? = reference.get() + + override fun set(value: Any?) { + reference.set(value) + } +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt index e575e316192..d9d249442b6 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt @@ -21,11 +21,11 @@ import java.lang.reflect.Modifier import kotlin.reflect.IllegalPropertyAccessException import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 +import kotlin.jvm.internal.MutablePropertyReference1 +import kotlin.jvm.internal.PropertyReference1 open class KProperty1Impl : DescriptorBasedProperty, KProperty1, KPropertyImpl { - constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super( - container, name, receiverParameterClass - ) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) @@ -56,10 +56,8 @@ open class KProperty1Impl : DescriptorBasedProperty, KProperty1, } -class KMutableProperty1Impl : KProperty1Impl, KMutableProperty1, KMutablePropertyImpl { - constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super( - container, name, receiverParameterClass - ) +open class KMutableProperty1Impl : KProperty1Impl, KMutableProperty1, KMutablePropertyImpl { + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) @@ -86,3 +84,33 @@ class KMutableProperty1Impl : KProperty1Impl, KMutableProperty1( + reference.getOwner() as KCallableContainerImpl, + reference.getName(), + reference.getSignature() +) { + override val name: String get() = reference.getName() + + override fun get(receiver: Any?): Any? = reference.get(receiver) +} + + +class KMutableProperty1FromReferenceImpl( + val reference: MutablePropertyReference1 +) : KMutableProperty1Impl( + reference.getOwner() as KCallableContainerImpl, + reference.getName(), + reference.getSignature() +) { + override val name: String get() = reference.getName() + + override fun get(receiver: Any?): Any? = reference.get(receiver) + + override fun set(receiver: Any?, value: Any?) { + reference.set(receiver, value) + } +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt index 9a65d8e8e88..d67def0ccd2 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -24,7 +24,7 @@ import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KProperty2 open class KProperty2Impl : DescriptorBasedProperty, KProperty2, KPropertyImpl { - constructor(container: KClassImpl, name: String, receiverParameterClass: Class) : super(container, name, receiverParameterClass) + constructor(container: KClassImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KClassImpl, descriptor: PropertyDescriptor) : super(container, descriptor) @@ -47,7 +47,7 @@ open class KProperty2Impl : DescriptorBasedProperty, KProperty2 : KProperty2Impl, KMutableProperty2, KMutablePropertyImpl { - constructor(container: KClassImpl, name: String, receiverParameterClass: Class) : super(container, name, receiverParameterClass) + constructor(container: KClassImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KClassImpl, descriptor: PropertyDescriptor) : super(container, descriptor) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index 8d7ef554cba..6f86ff69d36 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -16,8 +16,7 @@ package kotlin.reflect.jvm.internal; -import kotlin.jvm.internal.FunctionReference; -import kotlin.jvm.internal.ReflectionFactory; +import kotlin.jvm.internal.*; import kotlin.reflect.*; /** @@ -50,32 +49,34 @@ public class ReflectionFactoryImpl extends ReflectionFactory { // Properties @Override - public KProperty1 memberProperty(String name, KClass owner) { - return ((KClassImpl) owner).memberProperty(name); + public KProperty0 property0(PropertyReference0 p) { + return new KProperty0FromReferenceImpl(p); } @Override - public KMutableProperty1 mutableMemberProperty(String name, KClass owner) { - return ((KClassImpl) owner).mutableMemberProperty(name); + public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) { + return new KMutableProperty0FromReferenceImpl(p); } @Override - public KProperty0 topLevelVariable(String name, KPackage owner) { - return ((KPackageImpl) owner).topLevelVariable(name); + public KProperty1 property1(PropertyReference1 p) { + return new KProperty1FromReferenceImpl(p); } @Override - public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) { - return ((KPackageImpl) owner).mutableTopLevelVariable(name); + public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) { + return new KMutableProperty1FromReferenceImpl(p); } @Override - public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) { - return ((KPackageImpl) owner).topLevelExtensionProperty(name, receiver); + public KProperty2 property2(PropertyReference2 p) { + // TODO: support member extension property references + return p; } @Override - public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) { - return ((KPackageImpl) owner).mutableTopLevelExtensionProperty(name, receiver); + public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) { + // TODO: support member extension property references + return p; } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index 529f085bf47..934fd724c47 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -18,58 +18,25 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor import org.jetbrains.kotlin.load.java.sources.JavaSourceElement import org.jetbrains.kotlin.load.java.structure.* import org.jetbrains.kotlin.load.java.structure.reflect.* import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.platform.JavaToKotlinClassMap -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId -import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.TypeUtils import kotlin.reflect.KotlinReflectionInternalError object RuntimeTypeMapper { - // TODO: this logic must be shared with JetTypeMapper - fun mapTypeToJvmDesc(type: JetType): String { - val classifier = type.getConstructor().getDeclarationDescriptor() - if (classifier is TypeParameterDescriptor) { - return mapTypeToJvmDesc(classifier.getUpperBounds().first()) - } - - if (KotlinBuiltIns.isArray(type)) { - val elementType = KotlinBuiltIns.getInstance().getArrayElementType(type) - // makeNullable is called here to map primitive types to the corresponding wrappers, - // because the given type is Array, not SomethingArray - return "[" + mapTypeToJvmDesc(TypeUtils.makeNullable(elementType)) - } - - val classDescriptor = classifier as ClassDescriptor - val fqName = DescriptorUtils.getFqName(classDescriptor) - - KotlinBuiltIns.getPrimitiveTypeByFqName(fqName)?.let { primitiveType -> - val jvmType = JvmPrimitiveType.get(primitiveType) - return if (TypeUtils.isNullableType(type)) ClassId.topLevel(jvmType.getWrapperFqName()).desc else jvmType.getDesc() - } - - KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName)?.let { primitiveType -> - return "[" + JvmPrimitiveType.get(primitiveType).getDesc() - } - - JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName)?.let { return it.desc } - - return classDescriptor.classId.desc - } - fun mapSignature(function: FunctionDescriptor): String { if (function is DeserializedSimpleFunctionDescriptor) { val proto = function.getProto() @@ -125,6 +92,50 @@ object RuntimeTypeMapper { } } + fun mapPropertySignature(property: PropertyDescriptor): String { + if (property is DeserializedPropertyDescriptor) { + val proto = property.proto + val nameResolver = property.nameResolver + if (!proto.hasExtension(JvmProtoBuf.propertySignature)) { + throw KotlinReflectionInternalError("No metadata found for $property") + } + val signature = proto.getExtension(JvmProtoBuf.propertySignature) + val deserializer = SignatureDeserializer(nameResolver) + + if (signature.hasGetter()) { + return deserializer.methodSignatureString(signature.getGetter()) + } + + // In case the property doesn't have a getter, construct the signature of its imaginary default getter. + // See PropertyReference#getSignature + val field = signature.getField() + + // TODO: some kind of test on the Java Bean convention? + return getterName(nameResolver.getString(field.getName())) + + "()" + + deserializer.typeDescriptor(field.getType()) + } + else if (property is JavaPropertyDescriptor) { + val method = (property.getSource() as? JavaSourceElement)?.javaElement as? JavaField ?: + throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property") + + return StringBuilder { + append(getterName(method.getName().asString())) + append("()") + appendJavaType(method.getType()) + }.toString() + } + else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})") + } + + private fun getterName(propertyName: String): String { + return JvmAbi.GETTER_PREFIX + propertyName.capitalizeWithJavaBeanConvention() + } + + private fun String.capitalizeWithJavaBeanConvention(): String { + return if (length() > 1 && this[1].isUpperCase()) this else capitalize() + } + fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId { if (klass.isArray()) { klass.getComponentType().primitiveType?.let { @@ -147,7 +158,4 @@ object RuntimeTypeMapper { private val Class<*>.primitiveType: PrimitiveType? get() = if (isPrimitive()) JvmPrimitiveType.get(getSimpleName()).getPrimitiveType() else null - - private val ClassId.desc: String - get() = "L${JvmClassName.byClassId(this).getInternalName()};" } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt index 34f8ef44fb5..be860b2dc80 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -95,17 +95,10 @@ public val Field.kotlin: KProperty<*>? get() { if (isSynthetic()) return null - val clazz = getDeclaringClass() - val name = getName() - val modifiers = getModifiers() - val static = Modifier.isStatic(modifiers) - val final = Modifier.isFinal(modifiers) - if (static) { - val kPackage = clazz.kotlinPackage - return if (final) Reflection.topLevelVariable(name, kPackage) else Reflection.mutableTopLevelVariable(name, kPackage) - } - else { - val kClass = clazz.kotlin - return if (final) Reflection.memberProperty(name, kClass) else Reflection.mutableMemberProperty(name, kClass) + val clazz = getDeclaringClass().kotlin as KClassImpl + + // TODO: optimize (search by name) + return clazz.properties.firstOrNull { p: KProperty<*> -> + (p as KPropertyImpl<*>).field == this } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java new file mode 100644 index 00000000000..d0bb16a299b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/CallableReference.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.jvm.KotlinReflectionNotSupportedError; +import kotlin.reflect.KCallable; +import kotlin.reflect.KDeclarationContainer; + +/** + * A superclass for all classes generated by Kotlin compiler for callable references. + * + * All methods from reflection API should be implemented here to throw informative exceptions (see KotlinReflectionNotSupportedError) + */ +public abstract class CallableReference implements KCallable { + + // The following methods provide the information identifying this callable, which is used by the reflection implementation. + // They are supposed to be overridden in each subclass (each anonymous class generated for a callable reference). + + /** + * @return the class or package where the callable should be located, usually specified on the LHS of the '::' operator + */ + public KDeclarationContainer getOwner() { + throw error(); + } + + /** + * @return Kotlin name of the callable, the one which was declared in the source code (@platformName doesn't change it) + */ + @Override + public String getName() { + throw error(); + } + + /** + * @return JVM signature of the callable, e.g. "println(Ljava/lang/Object;)V". If this is a property reference, + * returns the JVM signature of its getter, e.g. "getFoo(Ljava/lang/String;)I". If the property has no getter in the bytecode + * (e.g. private property in a class), it's still the signature of the imaginary default getter that would be generated otherwise. + * + * Note that technically the signature itself is not even used as a signature per se in reflection implementation, + * but only as a unique and unambiguous way to map a function/property descriptor to a string. + */ + public String getSignature() { + throw error(); + } + + // The following methods are the stub implementations of reflection functions. + // They are called when you're using reflection on a property reference without the reflection implementation in the classpath. + + // (nothing here yet) + + protected static Error error() { + throw new KotlinReflectionNotSupportedError(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java index 8b7511305d7..6aff6021d97 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java @@ -37,29 +37,22 @@ public class FunctionReference extends FunctionImpl implements KFunction { return arity; } - // The following methods provide the information identifying this function, which is used by the reflection implementation. - // They are supposed to be overridden in each subclass (each anonymous class generated for a function reference). + // Most of the following methods are copies from CallableReference, since this class cannot inherit from it public KDeclarationContainer getOwner() { throw error(); } - // Kotlin name of the function, the one which was declared in the source code (@platformName can't change it) + @Override public String getName() { throw error(); } - // JVM signature of the function, e.g. "println(Ljava/lang/Object;)V" public String getSignature() { throw error(); } - // The following methods are the stub implementations of reflection functions. - // They are called when you're using reflection on a function reference without the reflection implementation in the classpath. - - // (nothing here yet) - - private static Error error() { + protected static Error error() { throw new KotlinReflectionNotSupportedError(); } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference.java new file mode 100644 index 00000000000..b5c4b6b7771 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference.java @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KMutableProperty; + +public abstract class MutablePropertyReference extends PropertyReference implements KMutableProperty { +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java new file mode 100644 index 00000000000..6b19fdcac72 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KMutableProperty0; + +public class MutablePropertyReference0 extends MutablePropertyReference implements KMutableProperty0 { + @Override + public Object get() { + throw error(); + } + + @Override + public void set(Object value) { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java new file mode 100644 index 00000000000..44bd0b747db --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KMutableProperty1; + +public class MutablePropertyReference1 extends MutablePropertyReference implements KMutableProperty1 { + @Override + public Object get(Object receiver) { + throw error(); + } + + @Override + public void set(Object receiver, Object value) { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java new file mode 100644 index 00000000000..eb6688fb5c1 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KMutableProperty2; + +public class MutablePropertyReference2 extends MutablePropertyReference implements KMutableProperty2 { + @Override + public Object get(Object receiver1, Object receiver2) { + throw error(); + } + + @Override + public void set(Object receiver1, Object receiver2, Object value) { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java new file mode 100644 index 00000000000..822d9fc9af2 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference.java @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KProperty; + +public abstract class PropertyReference extends CallableReference implements KProperty { +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java new file mode 100644 index 00000000000..0c07baf59ff --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KProperty0; + +public class PropertyReference0 extends PropertyReference implements KProperty0 { + @Override + public Object get() { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java new file mode 100644 index 00000000000..3a5df99f07d --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KProperty1; + +public class PropertyReference1 extends PropertyReference implements KProperty1 { + @Override + public Object get(Object receiver) { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java new file mode 100644 index 00000000000..b04fe85ebaa --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KProperty2; + +public class PropertyReference2 extends PropertyReference implements KProperty2 { + @Override + public Object get(Object receiver1, Object receiver2) { + throw error(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java b/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java index e839eeb1196..26bfe9fa704 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java @@ -67,27 +67,27 @@ public class Reflection { // Properties - public static KProperty1 memberProperty(String name, KClass owner) { - return factory.memberProperty(name, owner); + public static KProperty0 property0(PropertyReference0 p) { + return factory.property0(p); } - public static KMutableProperty1 mutableMemberProperty(String name, KClass owner) { - return factory.mutableMemberProperty(name, owner); + public static KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) { + return factory.mutableProperty0(p); } - public static KProperty0 topLevelVariable(String name, KPackage owner) { - return factory.topLevelVariable(name, owner); + public static KProperty1 property1(PropertyReference1 p) { + return factory.property1(p); } - public static KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) { - return factory.mutableTopLevelVariable(name, owner); + public static KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) { + return factory.mutableProperty1(p); } - public static KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) { - return factory.topLevelExtensionProperty(name, owner, receiver); + public static KProperty2 property2(PropertyReference2 p) { + return factory.property2(p); } - public static KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) { - return factory.mutableTopLevelExtensionProperty(name, owner, receiver); + public static KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) { + return factory.mutableProperty2(p); } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java index 13b310e76fa..05adf0b59b7 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java @@ -40,28 +40,28 @@ public class ReflectionFactory { // Properties - public KProperty1 memberProperty(String name, KClass owner) { - throw error(); + public KProperty0 property0(PropertyReference0 p) { + return p; } - public KMutableProperty1 mutableMemberProperty(String name, KClass owner) { - throw error(); + public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) { + return p; } - public KProperty0 topLevelVariable(String name, KPackage owner) { - throw error(); + public KProperty1 property1(PropertyReference1 p) { + return p; } - public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) { - throw error(); + public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) { + return p; } - public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) { - throw error(); + public KProperty2 property2(PropertyReference2 p) { + return p; } - public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) { - throw error(); + public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) { + return p; } private Error error() {