Added support of callable references on suspend functions

This commit is contained in:
Igor Chevdar
2019-07-18 15:54:39 +03:00
parent b511ff9472
commit 11e2fd5074
7 changed files with 151 additions and 63 deletions
@@ -37,6 +37,8 @@ class KonanReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
fun getKFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KFunction$n")
fun getKSuspendFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KSuspendFunction$n")
val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
@@ -44,6 +46,7 @@ class KonanReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
val kTypeProjection: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
val kSuspendFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
val kProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
val kProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
val kProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
@@ -385,6 +385,7 @@ internal class KonanSymbols(context: Context, private val symbolTable: SymbolTab
val refClass = symbolTable.referenceClass(context.getKonanInternalClass("Ref"))
val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
val kSuspendFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kSuspendFunctionImpl)
val kMutableProperty0 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0)
val kMutableProperty1 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1)
@@ -486,6 +487,10 @@ internal class KonanSymbols(context: Context, private val symbolTable: SymbolTab
val kFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(context.reflectionTypes.getKFunction(it)) }
// Since KSuspendFunctionN inherits Function{N+1} and we only have 0..22 range, skip the last one for now.
val kSuspendFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS - 1)
.map { symbolTable.referenceClass(context.reflectionTypes.getKSuspendFunction(it)) }
fun getKFunctionType(returnType: IrType, parameterTypes: List<IrType>): IrType {
val kFunctionClassSymbol = kFunctions[parameterTypes.size]
return kFunctionClassSymbol.typeWith(parameterTypes + returnType)
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
@@ -46,9 +44,6 @@ val IrTypeParameterSymbol.defaultType: IrType get() = IrSimpleTypeImpl(
fun IrClass.typeWith(arguments: List<IrType>) = this.symbol.typeWith(arguments)
fun IrType.makeNullableAsSpecified(nullable: Boolean): IrType =
if (nullable) this.makeNullable() else this.makeNotNull()
fun IrType.containsNull(): Boolean = if (this is IrSimpleType) {
if (this.hasQuestionMark) {
true
@@ -67,21 +62,3 @@ fun IrType.containsNull(): Boolean = if (this is IrSimpleType) {
// TODO: get rid of these:
fun IrType.isSubtypeOf(other: KotlinType): Boolean = this.toKotlinType().isSubtypeOf(other)
fun IrType.isSubtypeOf(other: IrType): Boolean = this.isSubtypeOf(other.toKotlinType())
val IrType.isFunctionOrKFunctionType: Boolean
get() = when (this) {
is IrSimpleType -> {
val kind = classifier.descriptor.getFunctionalClassKind()
kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
}
else -> false
}
internal tailrec fun IrType.getErasedTypeClass(): IrClassSymbol {
val classifier = this.classifierOrFail
return when (classifier) {
is IrClassSymbol -> classifier
is IrTypeParameterSymbol -> classifier.owner.superTypes.first().getErasedTypeClass()
else -> error(classifier)
}
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.ir.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
@@ -26,6 +25,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
@@ -103,7 +103,8 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
break
}
if (!expression.type.isFunctionOrKFunctionType) {
if (!expression.type.isFunction() && !expression.type.isKFunction()
&& !expression.type.isKSuspendFunction()) {
// Not a subject of this lowering.
return expression
}
@@ -131,9 +132,8 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val symbols = context.ir.symbols
private val irBuiltIns = context.irBuiltIns
private val continuationClassDescriptor = symbols.continuationClassDescriptor
private val getContinuationSymbol = symbols.getContinuation
private val continuationClassSymbol = getContinuationSymbol.owner.returnType.classifierOrFail as IrClassSymbol
private inner class FunctionReferenceBuilder(val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) {
@@ -183,48 +183,58 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
)
}
private val kFunctionImplSymbol = symbols.kFunctionImpl
private fun IrClass.getInvokeFunction() = simpleFunctions().single { it.name.asString() == "invoke" }
private val kFunctionImplSymbol = symbols.kFunctionImpl
private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single()
private val kSuspendFunctionImplSymbol = symbols.kSuspendFunctionImpl
private val kSuspendFunctionImplConstructorSymbol = kSuspendFunctionImplSymbol.constructors.single()
val isKFunction = functionReference.type.isKFunction()
val isKSuspendFunction = functionReference.type.isKSuspendFunction()
fun build(): BuiltFunctionReference {
val superClassType = if (isKFunction) {
kFunctionImplSymbol.typeWith(referencedFunction.returnType)
} else {
irBuiltIns.anyType
}
val superTypes = mutableListOf(superClassType)
val numberOfParameters = unboundFunctionParameters.size
val functionIrClass = if (isKFunction) {
symbols.kFunctions[numberOfParameters].owner
} else {
symbols.functions[numberOfParameters].owner
}
val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + referencedFunction.returnType
superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters)
var suspendFunctionIrClass: IrClass? = null
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type
if (lastParameterType != null && lastParameterType.classifierOrNull?.descriptor == continuationClassDescriptor) {
lastParameterType as IrSimpleType
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionIrClass = symbols.suspendFunctions[numberOfParameters - 1].owner
val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType)
superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters)
val superTypes = mutableListOf<IrType>()
val functionClass: IrClass
val suspendFunctionClass: IrClass?
if (isKSuspendFunction) {
superTypes += kSuspendFunctionImplSymbol.typeWith(referencedFunction.returnType)
functionClass = symbols.functions[numberOfParameters + 1].owner
val continuationType = continuationClassSymbol.typeWith(referencedFunction.returnType)
superTypes += functionClass.typeWith(functionParameterTypes + continuationType + irBuiltIns.anyNType)
suspendFunctionClass = symbols.kSuspendFunctions[numberOfParameters].owner
superTypes += suspendFunctionClass.typeWith(functionParameterTypes + referencedFunction.returnType)
}
else {
superTypes += if (isKFunction)
kFunctionImplSymbol.typeWith(referencedFunction.returnType)
else
irBuiltIns.anyType
functionClass = (if (isKFunction) symbols.kFunctions else symbols.functions)[numberOfParameters].owner
superTypes += functionClass.typeWith(functionParameterTypes + referencedFunction.returnType)
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type
if (lastParameterType?.classifierOrNull != continuationClassSymbol)
suspendFunctionClass = null
else {
lastParameterType as IrSimpleType
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionClass = symbols.suspendFunctions[numberOfParameters - 1].owner
val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType)
superTypes += suspendFunctionClass.symbol.typeWith(suspendFunctionClassTypeParameters)
}
}
val constructor = buildConstructor()
buildInvokeMethod(functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" })
suspendFunctionIrClass?.let { buildInvokeMethod(it.simpleFunctions().single { it.name.asString() == "invoke" }) }
if (!isKSuspendFunction)
buildInvokeMethod(functionClass.getInvokeFunction())
suspendFunctionClass?.let {
val invokeMethod = buildInvokeMethod(it.getInvokeFunction())
if (isKSuspendFunction)
invokeMethod.overriddenSymbols += functionClass.getInvokeFunction().symbol
}
functionReferenceClass.superTypes += superTypes
functionReferenceClass.addFakeOverrides()
@@ -254,9 +264,13 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
if (!isKFunction)
+irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single())
else +irDelegatingConstructorCall(kFunctionImplConstructorSymbol.owner).apply {
val superConstructor = when {
isKFunction -> kFunctionImplConstructorSymbol.owner
isKSuspendFunction -> kSuspendFunctionImplConstructorSymbol.owner
else -> irBuiltIns.anyClass.owner.constructors.single()
}
+irDelegatingConstructorCall(superConstructor).apply {
if (!isKFunction && !isKSuspendFunction) return@apply
// TODO: Remove as soon as IR declarations have their originalDescriptor.
val name = (referencedFunction.descriptor as? WrappedSimpleFunctionDescriptor)?.originalDescriptor?.name
?: referencedFunction.name
@@ -302,7 +316,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
this.createDispatchReceiverParameter()
superFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter ->
parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
parameter.copyTo(function, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
type = parameter.type.substitute(typeArgumentsMap))
}
@@ -21,6 +21,6 @@ open class KFunctionImpl<out R>(override val name: String, val fqName: String, v
}
override fun toString(): String {
return (if (name == "<init>") "constructor" else "function " + name) + " (Kotlin reflection is not available)"
return "${if (name == "<init>") "constructor" else "function " + name}"
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.native.internal
import kotlin.reflect.KType
import kotlin.reflect.KFunction
@FixmeReflection
internal abstract class KSuspendFunctionImpl<out R>(
override val name: String, val fqName: String,
val bound: Boolean, val receiver: Any?,
override val returnType: KType
): KFunction<R> {
override fun equals(other: Any?): Boolean {
if (other !is KSuspendFunctionImpl<*>) return false
return fqName == other.fqName && bound == other.bound && receiver == other.receiver
}
override fun hashCode(): Int {
return (fqName.hashCode() * 31 + if (bound) 1 else 0) * 31 + receiver.hashCode()
}
override fun toString(): String {
return "suspend function $name"
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:Suppress("SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE")
package kotlin.reflect
import kotlin.coroutines.*
// (0..22).joinToString("\n") { i -> "interface KSuspendFunction$i<${(1..i).joinToString("") { j -> "in P$j, " }}out R> : SuspendFunction$i<${(1..i).joinToString("") { j -> "P$j, " }}R>, KFunction<R>\n" }
interface KSuspendFunction0<out R> : SuspendFunction0<R>, KFunction<R>
interface KSuspendFunction1<in P1, out R> : SuspendFunction1<P1, R>, KFunction<R>
interface KSuspendFunction2<in P1, in P2, out R> : SuspendFunction2<P1, P2, R>, KFunction<R>
interface KSuspendFunction3<in P1, in P2, in P3, out R> : SuspendFunction3<P1, P2, P3, R>, KFunction<R>
interface KSuspendFunction4<in P1, in P2, in P3, in P4, out R> : SuspendFunction4<P1, P2, P3, P4, R>, KFunction<R>
interface KSuspendFunction5<in P1, in P2, in P3, in P4, in P5, out R> : SuspendFunction5<P1, P2, P3, P4, P5, R>, KFunction<R>
interface KSuspendFunction6<in P1, in P2, in P3, in P4, in P5, in P6, out R> : SuspendFunction6<P1, P2, P3, P4, P5, P6, R>, KFunction<R>
interface KSuspendFunction7<in P1, in P2, in P3, in P4, in P5, in P6, in P7, out R> : SuspendFunction7<P1, P2, P3, P4, P5, P6, P7, R>, KFunction<R>
interface KSuspendFunction8<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, out R> : SuspendFunction8<P1, P2, P3, P4, P5, P6, P7, P8, R>, KFunction<R>
interface KSuspendFunction9<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, out R> : SuspendFunction9<P1, P2, P3, P4, P5, P6, P7, P8, P9, R>, KFunction<R>
interface KSuspendFunction10<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, out R> : SuspendFunction10<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R>, KFunction<R>
interface KSuspendFunction11<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, out R> : SuspendFunction11<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R>, KFunction<R>
interface KSuspendFunction12<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, out R> : SuspendFunction12<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R>, KFunction<R>
interface KSuspendFunction13<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, out R> : SuspendFunction13<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R>, KFunction<R>
interface KSuspendFunction14<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, out R> : SuspendFunction14<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R>, KFunction<R>
interface KSuspendFunction15<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, out R> : SuspendFunction15<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R>, KFunction<R>
interface KSuspendFunction16<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, out R> : SuspendFunction16<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R>, KFunction<R>
interface KSuspendFunction17<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, out R> : SuspendFunction17<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R>, KFunction<R>
interface KSuspendFunction18<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, out R> : SuspendFunction18<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R>, KFunction<R>
interface KSuspendFunction19<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, out R> : SuspendFunction19<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R>, KFunction<R>
interface KSuspendFunction20<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, out R> : SuspendFunction20<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R>, KFunction<R>
interface KSuspendFunction21<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, out R> : SuspendFunction21<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R>, KFunction<R>
// Comment for now. The reason: https://github.com/JetBrains/kotlin/blob/ad1b795a69925e6ee8c79cbbd05cce8cd27a6704/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt#L555
//interface KSuspendFunction22<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : SuspendFunction22<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R>, KFunction<R>