Support KCallable.call

#KT-2187 Fixed
This commit is contained in:
Alexander Udalov
2015-07-16 21:45:28 +03:00
parent ffe32e0b6d
commit e079b8f425
22 changed files with 462 additions and 3 deletions
@@ -0,0 +1,62 @@
/*
* 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.reflect.jvm.internal
import java.lang.reflect.Constructor as ReflectConstructor
import java.lang.reflect.Method as ReflectMethod
internal sealed class FunctionCaller {
abstract fun call(args: Array<*>): Any?
class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller() {
override fun call(args: Array<*>): Any? {
return constructor.newInstance(*args)
}
}
abstract class Method(val method: ReflectMethod) : FunctionCaller() {
private val isVoidMethod = method.returnType == Void.TYPE
protected fun callMethod(instance: Any?, args: Array<*>): Any? {
val result = method.invoke(instance, *args)
// If this is a Unit function, the method returns void, Method#invoke returns null, while we should return Unit
return if (isVoidMethod) Unit else result
}
}
class StaticMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
return callMethod(null, args)
}
}
class InstanceMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
return callMethod(args[0], args.asList().subList(1, args.size()).toTypedArray())
}
}
class PlatformStaticInObject(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
if (args.isEmpty() || !method.declaringClass.isInstance(args[0])) {
throw IllegalArgumentException("A function in an object requires the object instance passed as the first argument.")
}
return callMethod(null, args.asList().subList(1, args.size()).toTypedArray())
}
}
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaConstructor
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaMethod
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.jvm.internal.FunctionImpl
import kotlin.reflect.*
@@ -68,7 +70,7 @@ open class KFunctionImpl protected constructor(
}
internal val javaMethod: Method? by ReflectProperties.lazySoft {
if (name != "<init>") {
if (!isConstructor) {
val proto = protoData
if (proto != null) {
container.findMethodBySignature(proto.proto, proto.signature, proto.nameResolver,
@@ -82,7 +84,7 @@ open class KFunctionImpl protected constructor(
}
internal val javaConstructor: Constructor<*>? by ReflectProperties.lazySoft {
if (name == "<init>") {
if (isConstructor) {
val proto = protoData
if (proto != null) {
return@lazySoft container.findConstructorBySignature(
@@ -98,6 +100,22 @@ open class KFunctionImpl protected constructor(
override val name: String get() = descriptor.getName().asString()
private val caller: FunctionCaller by ReflectProperties.lazySoft {
javaConstructor?.let { FunctionCaller.Constructor(it) } ?:
javaMethod?.let { method ->
when {
!Modifier.isStatic(method.modifiers) -> FunctionCaller.InstanceMethod(method)
descriptor.annotations.findAnnotation(PLATFORM_STATIC) != null -> FunctionCaller.PlatformStaticInObject(method)
else -> FunctionCaller.StaticMethod(method)
}
} ?:
throw KotlinReflectionInternalError("Call is not yet supported for this function: $descriptor")
}
override fun call(vararg args: Any?): Any? = caller.call(args)
private val isConstructor: Boolean get() = name == "<init>"
override fun getArity(): Int {
// TODO: test?
return descriptor.getValueParameters().size() +
@@ -113,4 +131,8 @@ open class KFunctionImpl protected constructor(
override fun toString(): String =
ReflectionObjectRenderer.renderFunction(descriptor)
private companion object {
val PLATFORM_STATIC = FqName("kotlin.platform.platformStatic")
}
}
@@ -45,6 +45,11 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty<R>, KProperty0<R>, KP
}
}
override fun call(vararg args: Any?): R {
require(args.isEmpty()) { "Property $name expects no arguments, but ${args.size()} were provided." }
return get()
}
class Getter<out R>(override val property: KProperty0Impl<R>) : KPropertyImpl.Getter<R>(), KProperty0.Getter<R> {
override fun invoke(): R = property.get()
}
@@ -70,6 +75,12 @@ open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, K
class Setter<R>(override val property: KMutableProperty0Impl<R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty0.Setter<R> {
override fun invoke(value: R): Unit = property.set(value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 1) { "Property setter for ${property.name} expects one argument, but ${args.size()} were provided." }
property.set(args.single() as R)
}
}
}
@@ -56,6 +56,12 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty<R>, KProperty1<T,
}
}
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?): R {
require(args.size() == 1) { "Property $name expects one argument, but ${args.size()} were provided." }
return get(args.single() as T)
}
class Getter<T, out R>(override val property: KProperty1Impl<T, R>) : KPropertyImpl.Getter<R>(), KProperty1.Getter<T, R> {
override fun invoke(receiver: T): R = property.get(receiver)
}
@@ -94,6 +100,12 @@ open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1
class Setter<T, R>(override val property: KMutableProperty1Impl<T, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty1.Setter<T, R> {
override fun invoke(receiver: T, value: R): Unit = property.set(receiver, value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 2) { "Property setter for ${property.name} expects two arguments, but ${args.size()} were provided." }
property.set(args[0] as T, args[1] as R)
}
}
}
@@ -46,6 +46,12 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty<R>, KProperty2<
}
}
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?): R {
require(args.size() == 2) { "Property $name expects two arguments, but ${args.size()} were provided." }
return get(args[0] as D, args[1] as E)
}
class Getter<D, E, out R>(override val property: KProperty2Impl<D, E, R>) : KPropertyImpl.Getter<R>(), KProperty2.Getter<D, E, R> {
override fun invoke(receiver1: D, receiver2: E): R = property.get(receiver1, receiver2)
}
@@ -72,5 +78,11 @@ class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty
class Setter<D, E, R>(override val property: KMutableProperty2Impl<D, E, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty2.Setter<D, E, R> {
override fun invoke(receiver1: D, receiver2: E, value: R): Unit = property.set(receiver1, receiver2, value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 3) { "Property setter for ${property.name} expects three arguments, but ${args.size()} were provided." }
property.set(args[0] as D, args[1] as E, args[2] as R)
}
}
}
@@ -45,6 +45,8 @@ interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
// TODO: default getter created this way won't have any source information
property.descriptor.getGetter() ?: DescriptorFactory.createDefaultGetter(property.descriptor)
}
override fun call(vararg args: Any?): R = property.call(*args)
}
}