Implement callSuspend and callSuspendBy functions as KCallable's

extension methods.
Also make isSuspend a member of KCallable.
 #KT-21972: Fixed
This commit is contained in:
Ilmir Usmanov
2018-08-18 00:05:05 +03:00
committed by Ilya Gorbunov
parent 66315cee45
commit e93683621a
16 changed files with 355 additions and 81 deletions
@@ -1,23 +1,15 @@
/*
* Copyright 2010-2016 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.
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("KCallables")
package kotlin.reflect.full
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
import kotlin.coroutines.Continuation
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.*
/**
* Returns a parameter representing the `this` instance needed to call this callable,
@@ -49,3 +41,26 @@ val KCallable<*>.valueParameters: List<KParameter>
fun KCallable<*>.findParameterByName(name: String): KParameter? {
return parameters.singleOrNull { it.name == name }
}
/**
* Calls a callable in the current suspend context. If the callable is not a suspend function, behaves as [KCallable.call].
* Otherwise, calls the suspend function with current continuation.
*/
@SinceKotlin("1.3")
suspend fun <R> KCallable<R>.callSuspend(vararg args: Any?): R {
if (!this.isSuspend) return call(*args)
if (this !is KFunction<*>) throw IllegalArgumentException("Cannot callSuspend on a property $this: suspend properties are not supported yet")
return suspendCoroutineUninterceptedOrReturn { call(*args, it) }
}
/**
* Calls a callable in the current suspend context. If the callable is not a suspend function, behaves as [KCallable.callBy].
* Otherwise, calls the suspend function with current continuation.
*/
@SinceKotlin("1.3")
suspend fun <R> KCallable<R>.callSuspendBy(args: Map<KParameter, Any?>): R {
if (!this.isSuspend) return callBy(args)
if (this !is KFunction<*>) throw IllegalArgumentException("Cannot callSuspendBy on a property $this: suspend properties are not supported yet")
val kCallable = asKCallableImpl() ?: throw KotlinReflectionInternalError("This callable does not support a default call: $this")
return suspendCoroutineUninterceptedOrReturn<R> { kCallable.callDefaultMethod(args, it) }
}
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.reflect.jvm.internal
@@ -21,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import java.lang.reflect.Type
import java.util.*
import kotlin.coroutines.Continuation
import kotlin.reflect.*
import kotlin.reflect.jvm.javaType
@@ -107,11 +97,11 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
}
override fun callBy(args: Map<KParameter, Any?>): R {
return if (isAnnotationConstructor) callAnnotationConstructor(args) else callDefaultMethod(args)
return if (isAnnotationConstructor) callAnnotationConstructor(args) else callDefaultMethod(args, null)
}
// See ArgumentGenerator#generate
private fun callDefaultMethod(args: Map<KParameter, Any?>): R {
internal fun callDefaultMethod(args: Map<KParameter, Any?>, continuationArgument: Continuation<*>?): R {
val parameters = parameters
val arguments = ArrayList<Any?>(parameters.size)
var mask = 0
@@ -144,6 +134,10 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
}
}
if (continuationArgument != null) {
arguments.add(continuationArgument)
}
if (!anyOptional) {
return call(*arguments.toTypedArray())
}
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.reflect.jvm.internal
@@ -120,6 +109,8 @@ internal abstract class KPropertyImpl<out R> private constructor(
override val isConst: Boolean get() = descriptor.isConst
override val isSuspend: Boolean get() = false
override fun equals(other: Any?): Boolean {
val that = other.asKPropertyImpl() ?: return false
return container == that.container && name == that.name && signature == that.signature && boundReceiver == that.boundReceiver