From 3e2fccc3f4082ce8a38fdb437d37cdb56eacb3c5 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 17 May 2017 13:55:41 +0300 Subject: [PATCH] Implemented inheritance of lambdas from SuspendFunction --- .../common/descriptors/DescriptorUtils.kt | 28 ++++++ .../kotlin/backend/konan/KonanPlatform.kt | 4 + .../konan/lower/CallableReferenceLowering.kt | 94 +++++++++++++------ .../konan/lower/SuspendFunctionsLowering.kt | 36 +++---- 4 files changed, 110 insertions(+), 52 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt index 89dd95e58fd..a4bd1149e3b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt @@ -18,6 +18,12 @@ package org.jetbrains.kotlin.backend.common.descriptors import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjectionImpl +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.replace internal val CallableDescriptor.isSuspend: Boolean get() = this is FunctionDescriptor && isSuspend @@ -65,3 +71,25 @@ fun CallableDescriptor.getOriginalParameter(parameter: ParameterDescriptor): Par this.extensionReceiverParameter -> this.original.extensionReceiverParameter!! else -> TODO("$parameter in $this") } + +fun KotlinType.replace(types: List) = this.replace(types.map(::TypeProjectionImpl)) + +fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor { + val typeSubstitutor = TypeSubstitutor.create( + typeParameters + .withIndex() + .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) }) + ) + return substitute(typeSubstitutor)!! +} + +fun ClassDescriptor.getFunction(name: String, types: List): FunctionDescriptor { + val typeSubstitutor = TypeSubstitutor.create( + declaredTypeParameters + .withIndex() + .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) }) + ) + return unsubstitutedMemberScope + .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!! +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt index 8a85fb239a2..b5ebb5fc910 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt @@ -41,6 +41,10 @@ class KonanBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageMana override fun getClassDescriptorFactories() = super.getClassDescriptorFactories() + KonanBuiltInClassDescriptorFactory(storageManager, builtInsModule) + override fun getSuspendFunction(parameterCount: Int): ClassDescriptor { + return getBuiltInClassByName(Name.identifier("SuspendFunction$parameterCount")) + } + object FqNames { val packageName = FqName("konan.internal") 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 587be21812d..6bb15b922fb 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass +import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionOrKFunctionType import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.ir.createFakeOverrideDescriptor @@ -47,16 +48,16 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.replace import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.backend.common.descriptors.* +import org.jetbrains.kotlin.types.* internal class CallableReferenceLowering(val context: Context): DeclarationContainerLoweringPass { @@ -112,6 +113,17 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta private class BuiltFunctionReference(val functionReferenceClass: IrClass, val functionReferenceConstructor: IrConstructor) + private val COROUTINES_FQ_NAME = FqName.fromSegments(listOf("kotlin", "coroutines", "experimental")) + private val KOTLIN_FQ_NAME = FqName("kotlin") + + private val coroutinesScope = context.irModule!!.descriptor.getPackage(COROUTINES_FQ_NAME).memberScope + private val kotlinPackageScope = context.irModule!!.descriptor.getPackage(KOTLIN_FQ_NAME).memberScope + + private val continuationClassDescriptor = coroutinesScope + .getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor + + private val getContinuationDescriptor = context.builtIns.getKonanInternalFunctions("getContinuation").single() + private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor, val functionReference: IrFunctionReference) { @@ -125,21 +137,33 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta private lateinit var functionReferenceThis: IrValueParameterSymbol private lateinit var argumentToPropertiesMap: Map - private fun KotlinType.replace(types: List) = this.replace(types.map(::TypeProjectionImpl)) - private val kFunctionImplClassDescriptor = context.builtIns.getKonanInternalClass("KFunctionImpl") fun build(): BuiltFunctionReference { val startOffset = functionReference.startOffset val endOffset = functionReference.endOffset + val returnType = functionDescriptor.returnType!! val superTypes = mutableListOf( - kFunctionImplClassDescriptor.defaultType.replace(listOf(functionDescriptor.returnType!!)) + kFunctionImplClassDescriptor.defaultType.replace(listOf(returnType)) ) + + val numberOfParameters = unboundFunctionParameters.size + val functionClassDescriptor = context.reflectionTypes.getKFunction(numberOfParameters) + val functionParameterTypes = unboundFunctionParameters.map { it.type } + val functionClassTypeParameters = functionParameterTypes + returnType + superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters) + var suspendFunctionClassDescriptor: ClassDescriptor? = null - val functionClassDescriptor = context.reflectionTypes.getKFunction(unboundFunctionParameters.size) - val types = unboundFunctionParameters.map { it.type } + functionDescriptor.returnType!! - superTypes += functionClassDescriptor.defaultType.replace(types) + var suspendFunctionClassTypeParameters: List? = null + val lastParameterType = unboundFunctionParameters.lastOrNull()?.type + if (lastParameterType != null && TypeUtils.getClassDescriptor(lastParameterType) == continuationClassDescriptor) { + // If the last parameter is Continuation<> inherit from SuspendFunction. + suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier( + Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor + suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type + superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters) + } functionReferenceClassDescriptor = ClassDescriptorImpl( /* containingDeclaration = */ containingDeclaration, @@ -156,27 +180,29 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, descriptor = functionReferenceClassDescriptor ) + functionReferenceClass.createParameterDeclarations() + functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol val constructorBuilder = createConstructorBuilder() - val typeSubstitutor = TypeSubstitutor.create( - functionClassDescriptor.declaredTypeParameters - .withIndex() - .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) }) - ) - val invokeFunctionDescriptor = functionClassDescriptor.unsubstitutedMemberScope - .getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!! + val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters) val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor) + var suspendInvokeMethodBuilder: SymbolWithIrBuilder? = null + if (suspendFunctionClassDescriptor != null) { + val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor.getFunction("invoke", suspendFunctionClassTypeParameters!!) + suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor) + } + val inheritedKFunctionImpl = kFunctionImplClassDescriptor.unsubstitutedMemberScope .getContributedDescriptors() .map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) } .filterNotNull() val contributedDescriptors = ( - inheritedKFunctionImpl + invokeMethodBuilder.symbol.descriptor - ).toList() + inheritedKFunctionImpl + invokeMethodBuilder.symbol.descriptor + suspendInvokeMethodBuilder?.symbol?.descriptor + ).filterNotNull().toList() functionReferenceClassDescriptor.initialize( SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null) @@ -186,6 +212,11 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta invokeMethodBuilder.initialize() functionReferenceClass.declarations.add(invokeMethodBuilder.ir) + suspendInvokeMethodBuilder?.let { + it.initialize() + functionReferenceClass.declarations.add(it.ir) + } + return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir) } @@ -266,7 +297,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta } } - private fun createInvokeMethodBuilder(functionInvokeFunctionDescriptor: FunctionDescriptor) + private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor) = object : SymbolWithIrBuilder() { override fun buildSymbol() = IrSimpleFunctionSymbolImpl( @@ -281,7 +312,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta override fun doInitialize() { val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl - val valueParameters = functionInvokeFunctionDescriptor.valueParameters + val valueParameters = superFunctionDescriptor.valueParameters .map { it.copyAsValueParameter(descriptor, it.index) } descriptor.initialize( @@ -289,21 +320,23 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta /* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter, /* typeParameters = */ emptyList(), /* unsubstitutedValueParameters = */ valueParameters, - /* unsubstitutedReturnType = */ functionInvokeFunctionDescriptor.returnType, + /* unsubstitutedReturnType = */ superFunctionDescriptor.returnType, /* modality = */ Modality.FINAL, /* visibility = */ Visibilities.PRIVATE).apply { - overriddenDescriptors += functionInvokeFunctionDescriptor + overriddenDescriptors += superFunctionDescriptor + isSuspend = superFunctionDescriptor.isSuspend } } override fun buildIr(): IrSimpleFunction { val startOffset = functionReference.startOffset val endOffset = functionReference.endOffset + val ourSymbol = symbol return IrFunctionImpl( startOffset = startOffset, endOffset = endOffset, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, - symbol = symbol).apply { + symbol = ourSymbol).apply { val function = this val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) @@ -316,10 +349,17 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta var unboundIndex = 0 val unboundArgsSet = unboundFunctionParameters.toSet() functionParameters.forEach { - val argument = if (unboundArgsSet.contains(it)) - irGet(valueParameters[unboundIndex++].symbol) - else - irGetField(irGet(functionReferenceThis), argumentToPropertiesMap[it]!!) + val argument = + if (!unboundArgsSet.contains(it)) + // Bound parameter - read from field. + irGetField(irGet(functionReferenceThis), argumentToPropertiesMap[it]!!) + else { + if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) + // For suspend functions the last argument is continuation and it is implicit. + irCall(getContinuationDescriptor.substitute(ourSymbol.descriptor.returnType!!)) + else + irGet(valueParameters[unboundIndex++].symbol) + } when (it) { functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt index c1461982a2e..d3b9e3983ce 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt @@ -50,11 +50,9 @@ import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.replace import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.makeNotNullable +import org.jetbrains.kotlin.backend.common.descriptors.* internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass { @@ -236,17 +234,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai private val getContinuationDescriptor = context.builtIns.getKonanInternalFunctions("getContinuation").single() private val returnIfSuspendedDescriptor = context.builtIns.getKonanInternalFunctions("returnIfSuspended").single() - private fun KotlinType.replace(types: List) = this.replace(types.map(::TypeProjectionImpl)) - - private fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor { - val typeSubstitutor = TypeSubstitutor.create( - typeParameters - .withIndex() - .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) }) - ) - return substitute(typeSubstitutor)!! - } - private fun removeReturnIfSuspendedCall(irFunction: IrFunction) { irFunction.transformChildrenVoid(object: IrElementTransformerVoid() { override fun visitCall(expression: IrCall): IrExpression { @@ -332,22 +319,23 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai val superTypes = mutableListOf(coroutineImplClassDescriptor.defaultType) var suspendFunctionClassDescriptor: ClassDescriptor? = null var functionClassDescriptor: ClassDescriptor? = null + var suspendFunctionClassTypeArguments: List? = null + var functionClassTypeArguments: List? = null if (unboundFunctionParameters != null) { // Suspend lambda inherits SuspendFunction. val numberOfParameters = unboundFunctionParameters.size suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier( Name.identifier("SuspendFunction$numberOfParameters"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor - superTypes += suspendFunctionClassDescriptor.defaultType.replace( - unboundFunctionParameters.map { it.type } + irFunction.descriptor.returnType!! - ) + val unboundParameterTypes = unboundFunctionParameters.map { it.type } + suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!! + superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments) functionClassDescriptor = kotlinPackageScope.getContributedClassifier( Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!)) - superTypes += functionClassDescriptor.defaultType.replace( - unboundFunctionParameters.map { it.type } // Main arguments, - + continuationType // and continuation. - + context.builtIns.nullableAnyType) // Return type + functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType + superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments) + } coroutineClassDescriptor = ClassDescriptorImpl( /* containingDeclaration = */ irFunction.descriptor.containingDeclaration, @@ -397,10 +385,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai if (createFunctionDescriptor != null) overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor - val invokeFunctionDescriptor = functionClassDescriptor!!.unsubstitutedMemberScope - .getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single() - val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor!!.unsubstitutedMemberScope - .getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single() + val invokeFunctionDescriptor = functionClassDescriptor!!.getFunction("invoke", functionClassTypeArguments!!) + val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor!!.getFunction("invoke", suspendFunctionClassTypeArguments!!) invokeMethodBuilder = createInvokeMethodBuilder( suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, functionInvokeFunctionDescriptor = invokeFunctionDescriptor,