[K/N] Use suspend function desugaring lowerings.

This commit is contained in:
Pavel Kunyavskiy
2022-09-05 16:14:29 +02:00
committed by Space Team
parent 8886e1b8b4
commit 817dba8564
19 changed files with 227 additions and 169 deletions
@@ -20,6 +20,7 @@ interface Mapping {
val capturedConstructors: Delegate<IrConstructor, IrConstructor>
val reflectedNameAccessor: Delegate<IrClass, IrSimpleFunction>
val suspendFunctionsToFunctionWithContinuations: Delegate<IrSimpleFunction, IrSimpleFunction>
val functionWithContinuationsToSuspendFunctions: Delegate<IrSimpleFunction, IrSimpleFunction>
abstract class Delegate<K : IrDeclaration, V> {
abstract operator fun get(key: K): V?
@@ -77,6 +78,7 @@ open class DefaultMapping(delegateFactory: DelegateFactory = DefaultDelegateFact
override val capturedConstructors: Mapping.Delegate<IrConstructor, IrConstructor> = delegateFactory.newDeclarationToDeclarationMapping()
override val reflectedNameAccessor: Mapping.Delegate<IrClass, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
override val suspendFunctionsToFunctionWithContinuations: Mapping.Delegate<IrSimpleFunction, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
override val functionWithContinuationsToSuspendFunctions: Mapping.Delegate<IrSimpleFunction, IrSimpleFunction> = delegateFactory.newDeclarationToDeclarationMapping()
}
fun <V : Any> KMutableProperty0<V?>.getOrPut(fn: () -> V) = this.get() ?: fn().also {
@@ -6,8 +6,6 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
@@ -19,7 +17,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
@@ -33,9 +30,6 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
protected abstract val stateMachineMethodName: Name
protected abstract fun getCoroutineBaseClass(function: IrFunction): IrClassSymbol
protected abstract fun nameForCoroutineClass(function: IrFunction): Name
protected abstract fun IrBuilderWithScope.launchSuspendFunctionWithGivenContinuation(
symbol: IrSimpleFunctionSymbol, superQualifierSymbol: IrClassSymbol?, dispatchReceiver: IrExpression,
arguments: List<IrExpression>, continuation: IrExpression) : IrExpression
protected abstract fun buildStateMachine(
stateMachineFunction: IrFunction,
@@ -57,106 +51,6 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
markSuspendLambdas(irFile)
buildCoroutines(irFile)
transformCallableReferencesToSuspendLambdas(irFile)
addMissingSupertypesToSuspendFunctionImplementingClasses(irFile)
}
private fun addMissingSupertypesToSuspendFunctionImplementingClasses(irFile: IrFile) {
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
// Don't need to iterate through children. All local classes are already moved to the top level by this moment.
}
override fun visitClass(declaration: IrClass) {
addMissingSupertypes(declaration)
declaration.acceptChildrenVoid(this)
}
private fun addMissingSupertypes(clazz: IrClass) {
val suspendFunctionTypes = getAllSubstitutedSupertypes(clazz).filter {
// SuspendFunction class is some hack in old Kotlin/Native compiler versions.
// It's not used now, but is considered as SuspendFunction-like class in isSuspendFunction util,
// if found in old klib. We need just to ignore it.
it.isSuspendFunction() && it.classOrNull?.owner?.name?.toString() != "SuspendFunction"
}.toSet()
for (suspendFunctionType in suspendFunctionTypes) {
val suspendFunctionClassSymbol = suspendFunctionType.classOrNull ?: continue
val suspendFunction = suspendFunctionClassSymbol.owner.simpleFunctions().single {
it.name == OperatorNameConventions.INVOKE
}
val invokeFunction = clazz.simpleFunctions().single {
it.name == OperatorNameConventions.INVOKE && it.overrides(suspendFunction)
}
if (invokeFunction.modality == Modality.ABSTRACT) {
continue
}
val suspendFunctionArity = suspendFunction.valueParameters.size
val functionClassSymbol = symbols.functionN(suspendFunctionArity + 1)
val functionSymbol = functionClassSymbol.owner.simpleFunctions().single {
it.name == OperatorNameConventions.INVOKE
}.symbol
val functionClassTypeArguments = suspendFunctionType.arguments.mapIndexed { index, argument ->
val type = (argument as IrTypeProjection).type
if (index == suspendFunctionArity) continuationClassSymbol.typeWith(type) else type
} + context.irBuiltIns.anyNType
val functionType = functionClassSymbol.typeWith(functionClassTypeArguments)
clazz.superTypes += functionType
context.irFactory.buildFun {
startOffset = SYNTHETIC_OFFSET
endOffset = SYNTHETIC_OFFSET
origin = DECLARATION_ORIGIN_COROUTINE_IMPL
name = OperatorNameConventions.INVOKE
visibility = DescriptorVisibilities.PROTECTED
returnType = context.irBuiltIns.anyNType
}.apply {
parent = clazz
clazz.declarations += this
typeParameters = invokeFunction.typeParameters.map { parameter ->
parameter.copyToWithoutSuperTypes(this, origin = DECLARATION_ORIGIN_COROUTINE_IMPL)
.apply { superTypes += parameter.superTypes }
}
valueParameters = invokeFunction.valueParameters
.mapIndexed { index, parameter ->
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
}
valueParameters += buildValueParameter(this) {
index = valueParameters.size
type = context.irBuiltIns.anyNType
name = "completion".synthesizedName
}
this.createDispatchReceiverParameter()
overriddenSymbols += functionSymbol
val thisReceiver = dispatchReceiverParameter!!
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
launchSuspendFunctionWithGivenContinuation(
invokeFunction.symbol,
superQualifierSymbol = invokeFunction.parentAsClass.symbol, // Call non-virtually.
irGet(thisReceiver),
valueParameters.dropLast(1).map { irGet(it) },
irGet(valueParameters.last())
)
)
}
}
}
}
})
}
private fun buildCoroutines(irFile: IrFile) {
@@ -433,7 +327,9 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
)
val suspendInvokeFunction =
suspendFunctionClass!!.simpleFunctions().single { it.name == OperatorNameConventions.INVOKE }
suspendFunctionClass!!.simpleFunctions().single { it.name == OperatorNameConventions.INVOKE }.let {
context.mapping.functionWithContinuationsToSuspendFunctions[it] ?: it
}
buildInvokeMethod(
functionInvokeFunction = suspendInvokeFunction,
@@ -722,3 +618,5 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
private val CREATE_IDENTIFIER = Name.identifier("create")
}
}
@@ -226,7 +226,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
body = context.createIrBuilder(symbol).irBlockBody {
+irReturn(
irCall(
wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }.symbol,
getSuspendFunctionWithoutContinuation(wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }).symbol,
originalSuperMethod.returnType
).apply {
dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), field)
@@ -88,12 +88,14 @@ private fun transformSuspendFunction(context: CommonBackendContext, function: Ir
fun IrSimpleFunction.getOrCreateFunctionWithContinuationStub(context: CommonBackendContext): IrSimpleFunction {
return context.mapping.suspendFunctionsToFunctionWithContinuations.getOrPut(this) {
createSuspendFunctionStub(context)
createSuspendFunctionStub(context).also {
context.mapping.functionWithContinuationsToSuspendFunctions[it] = this
}
}
}
private fun IrSimpleFunction.createSuspendFunctionStub(context: CommonBackendContext): IrSimpleFunction {
require(this.isSuspend)
require(this.isSuspend) { "$fqNameWhenAvailable should be a suspend function to create version with contunation" }
return factory.buildFun {
updateFrom(this@createSuspendFunctionStub)
isSuspend = false
@@ -103,9 +105,9 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: CommonBackendCon
}.also { function ->
function.parent = parent
function.annotations += annotations
function.metadata = metadata
function.copyAnnotationsFrom(this)
function.copyAttributes(this)
function.copyTypeParametersFrom(this)
val substitutionMap = makeTypeParameterSubstitutionMap(this, function)