Fixed bug in coroutines lowering
Removed unnecessary returns & blocks from suspend function with delegating tail call.
This commit is contained in:
+22
-24
@@ -43,10 +43,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetVariableImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
@@ -125,26 +122,26 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class SuspendFunctionKind {
|
private sealed class SuspendFunctionKind {
|
||||||
NO_SUSPEND_CALLS,
|
object NO_SUSPEND_CALLS : SuspendFunctionKind()
|
||||||
DELEGATING,
|
class DELEGATING(val delegatingCall: IrCall) : SuspendFunctionKind()
|
||||||
NEEDS_STATE_MACHINE
|
object NEEDS_STATE_MACHINE : SuspendFunctionKind()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformSuspendFunction(irFunction: IrFunction, functionReference: IrFunctionReference?): List<IrDeclaration>? {
|
private fun transformSuspendFunction(irFunction: IrFunction, functionReference: IrFunctionReference?): List<IrDeclaration>? {
|
||||||
val suspendFunctionKind = getSuspendFunctionKind(irFunction)
|
val suspendFunctionKind = getSuspendFunctionKind(irFunction)
|
||||||
return when (suspendFunctionKind) {
|
return when (suspendFunctionKind) {
|
||||||
SuspendFunctionKind.NO_SUSPEND_CALLS -> {
|
is SuspendFunctionKind.NO_SUSPEND_CALLS -> {
|
||||||
removeReturnIfSuspendedCall(irFunction)
|
|
||||||
null // No suspend function calls - just an ordinary function.
|
null // No suspend function calls - just an ordinary function.
|
||||||
}
|
}
|
||||||
|
|
||||||
SuspendFunctionKind.DELEGATING -> { // Calls another suspend function at the end.
|
is SuspendFunctionKind.DELEGATING -> { // Calls another suspend function at the end.
|
||||||
removeReturnIfSuspendedCall(irFunction)
|
removeReturnIfSuspendedCallAndSimplifyDelegatingCall(
|
||||||
|
irFunction, suspendFunctionKind.delegatingCall)
|
||||||
null // No need in state machine.
|
null // No need in state machine.
|
||||||
}
|
}
|
||||||
|
|
||||||
SuspendFunctionKind.NEEDS_STATE_MACHINE -> {
|
is SuspendFunctionKind.NEEDS_STATE_MACHINE -> {
|
||||||
val coroutine = buildCoroutine(irFunction, functionReference) // Coroutine implementation.
|
val coroutine = buildCoroutine(irFunction, functionReference) // Coroutine implementation.
|
||||||
if (suspendLambdas.contains(irFunction.descriptor)) // Suspend lambdas are called through factory method <create>,
|
if (suspendLambdas.contains(irFunction.descriptor)) // Suspend lambdas are called through factory method <create>,
|
||||||
listOf(coroutine) // thus we can eliminate original body.
|
listOf(coroutine) // thus we can eliminate original body.
|
||||||
@@ -209,7 +206,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
|
|||||||
return when {
|
return when {
|
||||||
numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS
|
numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS
|
||||||
numberOfSuspendCalls == 1
|
numberOfSuspendCalls == 1
|
||||||
&& suspendCallAtEnd -> SuspendFunctionKind.DELEGATING
|
&& suspendCallAtEnd -> SuspendFunctionKind.DELEGATING(lastCall!!)
|
||||||
else -> SuspendFunctionKind.NEEDS_STATE_MACHINE
|
else -> SuspendFunctionKind.NEEDS_STATE_MACHINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,16 +215,17 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
|
|||||||
private val getContinuationSymbol = symbols.getContinuation
|
private val getContinuationSymbol = symbols.getContinuation
|
||||||
private val returnIfSuspendedDescriptor = context.getInternalFunctions("returnIfSuspended").single()
|
private val returnIfSuspendedDescriptor = context.getInternalFunctions("returnIfSuspended").single()
|
||||||
|
|
||||||
private fun removeReturnIfSuspendedCall(irFunction: IrFunction) {
|
private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) {
|
||||||
irFunction.transformChildrenVoid(object: IrElementTransformerVoid() {
|
val returnValue =
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
if (delegatingCall.descriptor.original == returnIfSuspendedDescriptor)
|
||||||
expression.transformChildrenVoid(this)
|
delegatingCall.getValueArgument(0)!!
|
||||||
|
else delegatingCall
|
||||||
if (expression.descriptor.original == returnIfSuspendedDescriptor)
|
context.createIrBuilder(irFunction.symbol).run {
|
||||||
return expression.getValueArgument(0)!!
|
val statements = (irFunction.body as IrBlockBody).statements
|
||||||
return expression
|
val lastStatement = statements.last()
|
||||||
}
|
assert (lastStatement == delegatingCall || lastStatement is IrReturn) { "Unexpected statement $lastStatement" }
|
||||||
})
|
statements[statements.size - 1] = irReturn(returnValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCoroutine(irFunction: IrFunction, functionReference: IrFunctionReference?): IrClass {
|
private fun buildCoroutine(irFunction: IrFunction, functionReference: IrFunctionReference?): IrClass {
|
||||||
|
|||||||
Reference in New Issue
Block a user