From 11e2fd50746d9589ef69f86649021f62026ebbfb Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Thu, 18 Jul 2019 15:54:39 +0300 Subject: [PATCH] Added support of callable references on suspend functions --- .../backend/konan/KonanReflectionTypes.kt | 3 + .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 5 + .../backend/konan/ir/IrTypeAsKotlinType.kt | 23 ----- .../konan/lower/CallableReferenceLowering.kt | 92 +++++++++++-------- .../kotlin/native/internal/KFunctionImpl.kt | 2 +- .../native/internal/KSuspendFunctionImpl.kt | 30 ++++++ .../kotlin/reflect/KSuspendFunctions.kt | 59 ++++++++++++ 7 files changed, 151 insertions(+), 63 deletions(-) create mode 100644 runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt create mode 100644 runtime/src/main/kotlin/kotlin/reflect/KSuspendFunctions.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanReflectionTypes.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanReflectionTypes.kt index 91975dae15b..e275f0e69db 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanReflectionTypes.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanReflectionTypes.kt @@ -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) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index b65511abe49..4f92ce2ed25 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -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 { val kFunctionClassSymbol = kFunctions[parameterTypes.size] return kFunctionClassSymbol.typeWith(parameterTypes + returnType) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrTypeAsKotlinType.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrTypeAsKotlinType.kt index decf537f86b..a52a178338f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrTypeAsKotlinType.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrTypeAsKotlinType.kt @@ -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) = 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) - } -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt index a104191a469..9aa7e345744 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt @@ -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() + 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)) } diff --git a/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt b/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt index b0592d9fce8..7812e149eb4 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt @@ -21,6 +21,6 @@ open class KFunctionImpl(override val name: String, val fqName: String, v } override fun toString(): String { - return (if (name == "") "constructor" else "function " + name) + " (Kotlin reflection is not available)" + return "${if (name == "") "constructor" else "function " + name}" } } \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt b/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt new file mode 100644 index 00000000000..cf2476d393b --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt @@ -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( + override val name: String, val fqName: String, + val bound: Boolean, val receiver: Any?, + override val returnType: KType +): KFunction { + + 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" + } +} diff --git a/runtime/src/main/kotlin/kotlin/reflect/KSuspendFunctions.kt b/runtime/src/main/kotlin/kotlin/reflect/KSuspendFunctions.kt new file mode 100644 index 00000000000..aee829d080a --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/reflect/KSuspendFunctions.kt @@ -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\n" } + +interface KSuspendFunction0 : SuspendFunction0, KFunction + +interface KSuspendFunction1 : SuspendFunction1, KFunction + +interface KSuspendFunction2 : SuspendFunction2, KFunction + +interface KSuspendFunction3 : SuspendFunction3, KFunction + +interface KSuspendFunction4 : SuspendFunction4, KFunction + +interface KSuspendFunction5 : SuspendFunction5, KFunction + +interface KSuspendFunction6 : SuspendFunction6, KFunction + +interface KSuspendFunction7 : SuspendFunction7, KFunction + +interface KSuspendFunction8 : SuspendFunction8, KFunction + +interface KSuspendFunction9 : SuspendFunction9, KFunction + +interface KSuspendFunction10 : SuspendFunction10, KFunction + +interface KSuspendFunction11 : SuspendFunction11, KFunction + +interface KSuspendFunction12 : SuspendFunction12, KFunction + +interface KSuspendFunction13 : SuspendFunction13, KFunction + +interface KSuspendFunction14 : SuspendFunction14, KFunction + +interface KSuspendFunction15 : SuspendFunction15, KFunction + +interface KSuspendFunction16 : SuspendFunction16, KFunction + +interface KSuspendFunction17 : SuspendFunction17, KFunction + +interface KSuspendFunction18 : SuspendFunction18, KFunction + +interface KSuspendFunction19 : SuspendFunction19, KFunction + +interface KSuspendFunction20 : SuspendFunction20, KFunction + +interface KSuspendFunction21 : SuspendFunction21, KFunction + +// Comment for now. The reason: https://github.com/JetBrains/kotlin/blob/ad1b795a69925e6ee8c79cbbd05cce8cd27a6704/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt#L555 +//interface KSuspendFunction22 : SuspendFunction22, KFunction