From dc84445e2e3c9dc2735f3c1914882d9c2d14556b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 11 Dec 2015 17:13:00 +0300 Subject: [PATCH] Inherit KProperty interfaces from function types To be able to write the following: listOfStrings.map(String::length) --- .../kotlin/codegen/inline/InlineCodegen.java | 10 +++++- .../property/invokePropertyReference.kt | 31 +++++++++++++++++++ .../reflection/properties/invokeKProperty.kt | 7 +++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 12 +++++++ core/builtins/src/kotlin/reflect/KProperty.kt | 6 ++-- .../reflect/jvm/internal/KProperty0Impl.kt | 2 ++ .../reflect/jvm/internal/KProperty1Impl.kt | 2 ++ .../reflect/jvm/internal/KProperty2Impl.kt | 2 ++ .../internal/MutablePropertyReference0.java | 5 +++ .../internal/MutablePropertyReference1.java | 5 +++ .../internal/MutablePropertyReference2.java | 5 +++ .../jvm/internal/PropertyReference0.java | 5 +++ .../jvm/internal/PropertyReference1.java | 5 +++ .../jvm/internal/PropertyReference2.java | 5 +++ 14 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/invokePropertyReference.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/properties/invokeKProperty.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index b76bf6dd20c..cc6c3a72d7e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.modules.TargetId; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; +import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; @@ -538,9 +539,16 @@ public class InlineCodegen extends CallGenerator { } /*lambda or callable reference*/ - public static boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) { + public boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) { //TODO deparenthisise typed KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression); + + if (deparenthesized instanceof KtCallableReferenceExpression) { + // TODO: support inline of property references passed to inlinable function parameters + SimpleFunctionDescriptor functionReference = state.getBindingContext().get(BindingContext.FUNCTION, deparenthesized); + if (functionReference == null) return false; + } + return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized); } diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/invokePropertyReference.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/invokePropertyReference.kt new file mode 100644 index 00000000000..617732ae7f0 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/invokePropertyReference.kt @@ -0,0 +1,31 @@ +var state = "" + +var topLevel: Int + get() { + state += "1" + return 42 + } + set(value) { + throw AssertionError("Nooo") + } + +class A { + val member: String + get() { + state += "2" + return "42" + } +} + +val A.ext: Any + get() { + state += "3" + return this + } + +fun box(): String { + (::topLevel)() + (A::member)(A()) + (A::ext)(A()) + return if (state == "123") "OK" else "Fail $state" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/invokeKProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/invokeKProperty.kt new file mode 100644 index 00000000000..b9337faa934 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/invokeKProperty.kt @@ -0,0 +1,7 @@ +import kotlin.reflect.declaredMemberProperties + +class A(val foo: String) + +fun box(): String { + return (A::class.declaredMemberProperties.single()).invoke(A("OK")) as String +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 57ddf3a806e..2478eae4597 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -816,6 +816,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("invokePropertyReference.kt") + public void testInvokePropertyReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/invokePropertyReference.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("javaBeanConvention.kt") public void testJavaBeanConvention() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt"); @@ -4191,6 +4197,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("invokeKProperty.kt") + public void testInvokeKProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/invokeKProperty.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("memberAndMemberExtensionWithSameName.kt") public void testMemberAndMemberExtensionWithSameName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/memberAndMemberExtensionWithSameName.kt"); diff --git a/core/builtins/src/kotlin/reflect/KProperty.kt b/core/builtins/src/kotlin/reflect/KProperty.kt index 55047d5ca74..481b0596f71 100644 --- a/core/builtins/src/kotlin/reflect/KProperty.kt +++ b/core/builtins/src/kotlin/reflect/KProperty.kt @@ -65,7 +65,7 @@ public interface KMutableProperty : KProperty { * Such property is either originally declared in a receiverless context such as a package, * or has the receiver bound to it. */ -public interface KProperty0 : KProperty { +public interface KProperty0 : KProperty, () -> R { /** * Returns the current value of the property. */ @@ -99,7 +99,7 @@ public interface KMutableProperty0 : KProperty0, KMutableProperty { * @param T the type of the receiver which should be used to obtain the value of the property. * @param R the type of the property. */ -public interface KProperty1 : KProperty { +public interface KProperty1 : KProperty, (T) -> R { /** * Returns the current value of the property. * @@ -144,7 +144,7 @@ public interface KMutableProperty1 : KProperty1, KMutableProperty * the type of the extension receiver. * @param R the type of the property. */ -public interface KProperty2 : KProperty { +public interface KProperty2 : KProperty, (D, E) -> R { /** * Returns the current value of the property. In case of the extension property in a class, * the instance of the class should be passed first and the instance of the extension receiver second. 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 0370d047491..5346a3c5413 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -31,6 +31,8 @@ internal open class KProperty0Impl : DescriptorBasedProperty, KPropert override fun get(): R = getter.call() + override fun invoke(): R = get() + class Getter(override val property: KProperty0Impl) : KPropertyImpl.Getter(), KProperty0.Getter { override fun invoke(): R = property.get() } 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 1a363f0ad6b..6c1c64ec419 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty1Impl.kt @@ -31,6 +31,8 @@ internal open class KProperty1Impl : DescriptorBasedProperty, KProp override fun get(receiver: T): R = getter.call(receiver) + override fun invoke(receiver: T): R = get(receiver) + class Getter(override val property: KProperty1Impl) : KPropertyImpl.Getter(), KProperty1.Getter { override fun invoke(receiver: T): R = property.get(receiver) } 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 8c190b87d28..590b825134b 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -31,6 +31,8 @@ internal open class KProperty2Impl : DescriptorBasedProperty, KP override fun get(receiver1: D, receiver2: E): R = getter.call(receiver1, receiver2) + override fun invoke(receiver1: D, receiver2: E): R = get(receiver1, receiver2) + class Getter(override val property: KProperty2Impl) : KPropertyImpl.Getter(), KProperty2.Getter { override fun invoke(receiver1: D, receiver2: E): R = property.get(receiver1, receiver2) } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java index 72a9d4c3d17..8024437d83e 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0.java @@ -36,6 +36,11 @@ public class MutablePropertyReference0 extends MutablePropertyReference implemen ((KMutableProperty0) getReflected()).set(value); } + @Override + public Object invoke() { + return get(); + } + @Override public KProperty0.Getter getGetter() { return ((KMutableProperty0) getReflected()).getGetter(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java index 48e5a73f027..53240f9d944 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1.java @@ -36,6 +36,11 @@ public class MutablePropertyReference1 extends MutablePropertyReference implemen ((KMutableProperty1) getReflected()).set(receiver, value); } + @Override + public Object invoke(Object receiver) { + return get(receiver); + } + @Override public KProperty1.Getter getGetter() { return ((KMutableProperty1) getReflected()).getGetter(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java index eca52cb7ed6..4faf79af25b 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2.java @@ -36,6 +36,11 @@ public class MutablePropertyReference2 extends MutablePropertyReference implemen ((KMutableProperty2) getReflected()).set(receiver1, receiver2, value); } + @Override + public Object invoke(Object receiver1, Object receiver2) { + return get(receiver1, receiver2); + } + @Override public KProperty2.Getter getGetter() { return ((KMutableProperty2) getReflected()).getGetter(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java index b1903c72458..56f3b4c5f84 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0.java @@ -30,6 +30,11 @@ public class PropertyReference0 extends PropertyReference implements KProperty0 return ((KProperty0) getReflected()).get(); } + @Override + public Object invoke() { + return get(); + } + @Override public KProperty0.Getter getGetter() { return ((KProperty0) getReflected()).getGetter(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java index 3f28a5314df..ebdc8c6e03e 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1.java @@ -30,6 +30,11 @@ public class PropertyReference1 extends PropertyReference implements KProperty1 return ((KProperty1) getReflected()).get(receiver); } + @Override + public Object invoke(Object receiver) { + return get(receiver); + } + @Override public KProperty1.Getter getGetter() { return ((KProperty1) getReflected()).getGetter(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java index ad479c46184..8fad86a3fc2 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2.java @@ -30,6 +30,11 @@ public class PropertyReference2 extends PropertyReference implements KProperty2 return ((KProperty2) getReflected()).get(receiver1, receiver2); } + @Override + public Object invoke(Object receiver1, Object receiver2) { + return get(receiver1, receiver2); + } + @Override public KProperty2.Getter getGetter() { return ((KProperty2) getReflected()).getGetter();