JVM_IR: move SuspendLambdaLowering next to FunctionReferenceLowering
#KT-42253 Fixed #KT-39434 Fixed
This commit is contained in:
+2
-2
@@ -69,8 +69,8 @@ private fun IrBody.move(
|
||||
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||
// Might be an inline lambda argument; if the function has already been moved out, visit it explicitly.
|
||||
if (expression.origin == IrStatementOrigin.LAMBDA || expression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION)
|
||||
if (expression.statements[0] !is IrFunction && expression.statements[1] is IrFunctionReference)
|
||||
(expression.statements[1] as IrFunctionReference).symbol.owner.transformChildrenVoid()
|
||||
if (expression.statements.lastOrNull() is IrFunctionReference && expression.statements.none { it is IrFunction })
|
||||
(expression.statements.last() as IrFunctionReference).symbol.owner.transformChildrenVoid()
|
||||
return super.visitBlock(expression)
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ internal val localDeclarationsPhase = makeIrFilePhase(
|
||||
object : VisibilityPolicy {
|
||||
override fun forClass(declaration: IrClass, inInlineFunctionScope: Boolean): DescriptorVisibility =
|
||||
if (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL ||
|
||||
declaration.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||
) {
|
||||
@@ -290,6 +291,7 @@ private val jvmFilePhases = listOf(
|
||||
moveOrCopyCompanionObjectFieldsPhase,
|
||||
inlineCallableReferenceToLambdaPhase,
|
||||
functionReferencePhase,
|
||||
suspendLambdaPhase,
|
||||
propertyReferencePhase,
|
||||
constPhase,
|
||||
propertiesPhase,
|
||||
@@ -336,7 +338,6 @@ private val jvmFilePhases = listOf(
|
||||
interfaceObjectCallsPhase,
|
||||
|
||||
tailCallOptimizationPhase,
|
||||
suspendLambdaPhase,
|
||||
addContinuationPhase,
|
||||
|
||||
innerClassesPhase,
|
||||
|
||||
+140
-212
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
@@ -36,15 +36,14 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
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.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -52,7 +51,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
internal val suspendLambdaPhase = makeIrFilePhase(
|
||||
::SuspendLambdaLowering,
|
||||
"SuspendLambda",
|
||||
"Transform suspend lambda into continuation classes"
|
||||
"Transform suspend lambdas into continuation classes"
|
||||
)
|
||||
|
||||
internal val addContinuationPhase = makeIrFilePhase(
|
||||
@@ -63,24 +62,10 @@ internal val addContinuationPhase = makeIrFilePhase(
|
||||
)
|
||||
|
||||
private abstract class SuspendLoweringBase(protected val context: JvmBackendContext) : FileLoweringPass {
|
||||
protected fun IrClass.createContinuationClassFor(
|
||||
parent: IrDeclarationParent,
|
||||
newOrigin: IrDeclarationOrigin,
|
||||
newVisibility: DescriptorVisibility
|
||||
): IrClass = context.irFactory.buildClass {
|
||||
name = Name.special("<Continuation>")
|
||||
origin = newOrigin
|
||||
visibility = newVisibility
|
||||
}.also { irClass ->
|
||||
irClass.createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
irClass.superTypes += defaultType
|
||||
irClass.parent = parent
|
||||
}
|
||||
|
||||
protected fun IrClass.addFunctionOverride(function: IrSimpleFunction): IrSimpleFunction =
|
||||
addFunction(function.name.asString(), function.returnType).apply {
|
||||
overriddenSymbols += function.symbol
|
||||
valueParameters += function.valueParameters.map { it.copyTo(this) }
|
||||
valueParameters = function.valueParameters.map { it.copyTo(this) }
|
||||
}
|
||||
|
||||
protected fun IrClass.addFunctionOverride(
|
||||
@@ -105,153 +90,118 @@ private abstract class SuspendLoweringBase(protected val context: JvmBackendCont
|
||||
context.ir.symbols.continuationClass.typeWith(returnType).makeNullable()
|
||||
}
|
||||
|
||||
private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLoweringBase(context) {
|
||||
private class SuspendLambdaInfo(val reference: IrFunctionReference, val isRestricted: Boolean) {
|
||||
val function = reference.symbol.owner
|
||||
val arity = (reference.type as IrSimpleType).arguments.size - 1
|
||||
val capturesCrossinline = function.valueParameters.any { reference.getValueArgument(it.index).isReadOfCrossinline() }
|
||||
lateinit var constructor: IrConstructor
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
val inlineReferences = mutableSetOf<IrCallableReference<*>>()
|
||||
val suspendLambdas = mutableMapOf<IrFunctionReference, SuspendLambdaInfo>()
|
||||
irFile.acceptChildren(object : IrInlineReferenceLocator(context) {
|
||||
override fun visitInlineReference(argument: IrCallableReference<*>) {
|
||||
inlineReferences.add(argument)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: IrDeclaration?) {
|
||||
expression.acceptChildren(this, data)
|
||||
if (expression.isSuspend && expression.shouldBeTreatedAsSuspendLambda() && expression !in inlineReferences) {
|
||||
val isRestricted = expression.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any {
|
||||
it.type.classOrNull?.signature == IdSignature.PublicSignature("kotlin.coroutines", "RestrictsSuspension", null, 0)
|
||||
} == true
|
||||
suspendLambdas[expression] = SuspendLambdaInfo(expression, isRestricted)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunctionReference.shouldBeTreatedAsSuspendLambda() =
|
||||
origin == IrStatementOrigin.LAMBDA ||
|
||||
origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE ||
|
||||
origin == IrStatementOrigin.SUSPEND_CONVERSION
|
||||
}, null)
|
||||
|
||||
for (lambda in suspendLambdas.values) {
|
||||
(lambda.function.parent as? IrDeclarationContainer)?.declarations?.remove(lambda.function)
|
||||
private fun IrFunction.capturesCrossinline(): Boolean {
|
||||
var result = false
|
||||
accept(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
if (!result) element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
functions.add(declaration)
|
||||
super.visitFunction(declaration)
|
||||
functions.remove(declaration)
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue) {
|
||||
result = result || (expression.isReadOfCrossinline() && expression.symbol.owner.parent !in functions)
|
||||
}
|
||||
|
||||
private val functions = mutableSetOf<IrFunction>()
|
||||
}, null)
|
||||
return result
|
||||
}
|
||||
|
||||
private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLoweringBase(context) {
|
||||
override fun lower(irFile: IrFile) {
|
||||
val inlineReferences = IrInlineReferenceLocator.scan(context, irFile)
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val info = suspendLambdas[expression] ?: return super.visitFunctionReference(expression)
|
||||
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).run {
|
||||
val expressionArguments = expression.getArguments().map { it.second }
|
||||
irBlock {
|
||||
+generateContinuationClassForLambda(
|
||||
info,
|
||||
currentDeclarationParent ?: error("No current declaration parent at ${expression.dump()}"),
|
||||
(currentFunction?.irElement as? IrFunction)?.isInline == true
|
||||
)
|
||||
val constructor = info.constructor
|
||||
assert(constructor.valueParameters.size == expressionArguments.size + 1) {
|
||||
"Inconsistency between callable reference to suspend lambda and the corresponding continuation"
|
||||
}
|
||||
+irCall(constructor.symbol).apply {
|
||||
expressionArguments.forEachIndexed { index, argument ->
|
||||
putValueArgument(index, argument)
|
||||
}
|
||||
// Pass null as completion parameter
|
||||
putValueArgument(expressionArguments.size, irNull())
|
||||
}
|
||||
}
|
||||
}.also { it.transformChildrenVoid(this) }
|
||||
private fun IrFunctionReference.shouldBeTreatedAsSuspendLambda() =
|
||||
isSuspend && (origin == IrStatementOrigin.LAMBDA || origin == IrStatementOrigin.SUSPEND_CONVERSION)
|
||||
|
||||
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||
val reference = expression.statements.lastOrNull() as? IrFunctionReference ?: return super.visitBlock(expression)
|
||||
if (reference.shouldBeTreatedAsSuspendLambda() && reference !in inlineReferences) {
|
||||
assert(expression.statements.size == 2 && expression.statements[0] is IrFunction)
|
||||
expression.transformChildrenVoid(this)
|
||||
val parent = currentDeclarationParent ?: error("No current declaration parent at ${reference.dump()}")
|
||||
return generateAnonymousObjectForLambda(reference, parent)
|
||||
}
|
||||
return super.visitBlock(expression)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun generateContinuationClassForLambda(
|
||||
info: SuspendLambdaInfo,
|
||||
parent: IrDeclarationParent,
|
||||
insideInlineFunction: Boolean
|
||||
): IrClass {
|
||||
val suspendLambda =
|
||||
if (info.isRestricted) context.ir.symbols.restrictedSuspendLambdaClass.owner
|
||||
else context.ir.symbols.suspendLambdaClass.owner
|
||||
return suspendLambda.createContinuationClassFor(
|
||||
parent,
|
||||
JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA,
|
||||
// Since inline functions can be inlined to different package, we should generate lambdas inside these functions
|
||||
// as public
|
||||
if (insideInlineFunction) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
).apply {
|
||||
copyAttributes(info.reference)
|
||||
val functionNClass = context.ir.symbols.getJvmFunctionClass(info.arity + 1)
|
||||
superTypes +=
|
||||
IrSimpleTypeImpl(
|
||||
functionNClass,
|
||||
hasQuestionMark = false,
|
||||
arguments = (info.function.explicitParameters.subList(0, info.arity).map { it.type }
|
||||
+ info.function.continuationType() + context.irBuiltIns.anyNType)
|
||||
.map { makeTypeProjection(it, Variance.INVARIANT) },
|
||||
annotations = emptyList()
|
||||
)
|
||||
private fun generateAnonymousObjectForLambda(reference: IrFunctionReference, parent: IrDeclarationParent) =
|
||||
context.createIrBuilder(reference.symbol).irBlock(reference.startOffset, reference.endOffset) {
|
||||
assert(reference.getArguments().isEmpty()) { "lambda with bound arguments: ${reference.render()}" }
|
||||
val continuation = generateContinuationClassForLambda(reference, parent)
|
||||
+continuation
|
||||
+irCall(continuation.constructors.single().symbol).apply {
|
||||
// Pass null as completion parameter
|
||||
putValueArgument(0, irNull())
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateContinuationClassForLambda(reference: IrFunctionReference, parent: IrDeclarationParent): IrClass =
|
||||
context.irFactory.buildClass {
|
||||
name = SpecialNames.NO_NAME_PROVIDED
|
||||
origin = JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
}.apply {
|
||||
this.parent = parent
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
copyAttributes(reference)
|
||||
|
||||
val function = reference.symbol.owner
|
||||
val isRestricted = reference.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any {
|
||||
it.type.classOrNull?.signature == IdSignature.PublicSignature("kotlin.coroutines", "RestrictsSuspension", null, 0)
|
||||
} == true
|
||||
val suspendLambda =
|
||||
if (isRestricted) context.ir.symbols.restrictedSuspendLambdaClass.owner
|
||||
else context.ir.symbols.suspendLambdaClass.owner
|
||||
val arity = (reference.type as IrSimpleType).arguments.size - 1
|
||||
val functionNClass = context.ir.symbols.getJvmFunctionClass(arity + 1)
|
||||
superTypes += suspendLambda.defaultType
|
||||
superTypes += functionNClass.typeWith(
|
||||
function.explicitParameters.subList(0, arity).map { it.type }
|
||||
+ function.continuationType()
|
||||
+ context.irBuiltIns.anyNType
|
||||
)
|
||||
|
||||
addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType, JavaDescriptorVisibilities.PACKAGE_VISIBILITY)
|
||||
|
||||
val receiverField = info.function.extensionReceiverParameter?.let {
|
||||
assert(info.arity != 0)
|
||||
// Do not put '$' at the start, to avoid being caught by inlineCodegenUtils.isCapturedFieldName()
|
||||
val parametersFields = function.explicitParameters.map {
|
||||
addField {
|
||||
name = Name.identifier("p\$")
|
||||
// NB extension receiver can't be crossinline
|
||||
// Rename `$this` to avoid being caught by inlineCodegenUtils.isCapturedFieldName()
|
||||
name = if (it.index < 0) Name.identifier("p\$") else it.name
|
||||
type = it.type
|
||||
origin = LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE
|
||||
type = it.type
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
isFinal = false
|
||||
visibility = if (it.index < 0) DescriptorVisibilities.PRIVATE else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
}
|
||||
|
||||
val parametersFields = info.function.valueParameters.map {
|
||||
addField {
|
||||
name = it.name
|
||||
type = it.type
|
||||
origin = if (it.isCrossinline)
|
||||
LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
|
||||
else
|
||||
LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE
|
||||
isFinal = info.reference.getValueArgument(it.index) != null
|
||||
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
}
|
||||
val fieldsForBound = parametersFields.filter { it.isFinal }
|
||||
val fieldsForUnbound = listOfNotNull(receiverField) + parametersFields.filter { !it.isFinal }
|
||||
val constructor = addPrimaryConstructorForLambda(info, fieldsForBound, insideInlineFunction)
|
||||
val constructor = addPrimaryConstructorForLambda(suspendLambda, arity)
|
||||
val invokeToOverride = functionNClass.functions.single {
|
||||
it.owner.valueParameters.size == info.arity + 1 && it.owner.name.asString() == "invoke"
|
||||
it.owner.valueParameters.size == arity + 1 && it.owner.name.asString() == "invoke"
|
||||
}
|
||||
val createToOverride = suspendLambda.symbol.functions.singleOrNull {
|
||||
it.owner.valueParameters.size == info.arity + 1 && it.owner.name.asString() == "create"
|
||||
it.owner.valueParameters.size == arity + 1 && it.owner.name.asString() == "create"
|
||||
}
|
||||
val invokeSuspend = addInvokeSuspendForLambda(info.function, parametersFields, receiverField)
|
||||
if (info.capturesCrossinline) {
|
||||
val invokeSuspend = addInvokeSuspendForLambda(function, parametersFields)
|
||||
if (function.capturesCrossinline()) {
|
||||
addInvokeSuspendForInlineForLambda(invokeSuspend)
|
||||
}
|
||||
if (createToOverride != null) {
|
||||
val create = addCreate(constructor, createToOverride, fieldsForBound, fieldsForUnbound)
|
||||
addInvokeCallingCreate(create, invokeSuspend, invokeToOverride)
|
||||
addInvokeCallingCreate(addCreate(constructor, createToOverride, parametersFields), invokeSuspend, invokeToOverride)
|
||||
} else {
|
||||
addInvokeCallingConstructor(constructor, invokeSuspend, invokeToOverride, fieldsForBound, fieldsForUnbound)
|
||||
addInvokeCallingConstructor(constructor, invokeSuspend, invokeToOverride, parametersFields)
|
||||
}
|
||||
|
||||
context.suspendLambdaToOriginalFunctionMap[attributeOwnerId as IrFunctionReference] = info.function
|
||||
|
||||
info.constructor = constructor
|
||||
context.suspendLambdaToOriginalFunctionMap[attributeOwnerId as IrFunctionReference] = function
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.addInvokeSuspendForLambda(
|
||||
irFunction: IrFunction,
|
||||
fields: List<IrField>,
|
||||
receiverField: IrField?
|
||||
): IrSimpleFunction {
|
||||
private fun IrClass.addInvokeSuspendForLambda(irFunction: IrFunction, fields: List<IrField>): IrSimpleFunction {
|
||||
val superMethod = context.ir.symbols.suspendLambdaClass.functions.single {
|
||||
it.owner.name.asString() == INVOKE_SUSPEND_METHOD_NAME && it.owner.valueParameters.size == 1 &&
|
||||
it.owner.valueParameters[0].type.isKotlinResult()
|
||||
@@ -261,7 +211,7 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val parameter = (expression.symbol.owner as? IrValueParameter)?.takeIf { it.parent == irFunction }
|
||||
?: return expression
|
||||
val field = if (parameter.index < 0) receiverField!! else fields[parameter.index]
|
||||
val field = fields[parameter.index + if (irFunction.extensionReceiverParameter != null) 1 else 0]
|
||||
val receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter!!.symbol)
|
||||
return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type, receiver)
|
||||
}
|
||||
@@ -278,7 +228,7 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
).apply {
|
||||
copyAttributes(invokeSuspend)
|
||||
generateErrorForInlineBody()
|
||||
valueParameters += invokeSuspend.valueParameters.map { it.copyTo(this) }
|
||||
valueParameters = invokeSuspend.valueParameters.map { it.copyTo(this) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,35 +257,29 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
constructor: IrFunction,
|
||||
invokeSuspend: IrSimpleFunction,
|
||||
invokeToOverride: IrSimpleFunctionSymbol,
|
||||
fieldsForBound: List<IrField>,
|
||||
fieldsForUnbound: List<IrField>
|
||||
) = addFunctionOverride(invokeToOverride.owner) { function ->
|
||||
+irReturn(callInvokeSuspend(invokeSuspend, cloneLambda(function, constructor, fieldsForBound, fieldsForUnbound)))
|
||||
+irReturn(callInvokeSuspend(invokeSuspend, cloneLambda(function, constructor, fieldsForUnbound)))
|
||||
}
|
||||
|
||||
private fun IrClass.addCreate(
|
||||
constructor: IrFunction,
|
||||
createToOverride: IrSimpleFunctionSymbol,
|
||||
fieldsForBound: List<IrField>,
|
||||
fieldsForUnbound: List<IrField>
|
||||
) = addFunctionOverride(createToOverride.owner) { function ->
|
||||
+irReturn(cloneLambda(function, constructor, fieldsForBound, fieldsForUnbound))
|
||||
+irReturn(cloneLambda(function, constructor, fieldsForUnbound))
|
||||
}
|
||||
|
||||
private fun IrBlockBodyBuilder.cloneLambda(
|
||||
scope: IrFunction,
|
||||
constructor: IrFunction,
|
||||
fieldsForBound: List<IrField>,
|
||||
fieldsForUnbound: List<IrField>
|
||||
): IrExpression {
|
||||
val constructorCall = irCall(constructor).also {
|
||||
for (typeParameter in constructor.parentAsClass.typeParameters) {
|
||||
it.putTypeArgument(typeParameter.index, typeParameter.defaultType)
|
||||
}
|
||||
for ((index, field) in fieldsForBound.withIndex()) {
|
||||
it.putValueArgument(index, irGetField(irGet(scope.dispatchReceiverParameter!!), field))
|
||||
}
|
||||
it.putValueArgument(fieldsForBound.size, irGet(scope.valueParameters.last()))
|
||||
it.putValueArgument(0, irGet(scope.valueParameters.last()))
|
||||
}
|
||||
if (fieldsForUnbound.isEmpty()) {
|
||||
return constructorCall
|
||||
@@ -347,44 +291,26 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin
|
||||
return irGet(result)
|
||||
}
|
||||
|
||||
private fun IrBlockBodyBuilder.callInvokeSuspend(invokeSuspend: IrSimpleFunction, lambda: IrExpression): IrExpression {
|
||||
// SingletonReferencesLowering has finished a while ago, so `irUnit()` won't work anymore.
|
||||
val unitClass = context.irBuiltIns.unitClass
|
||||
val unitField = this@SuspendLambdaLowering.context.cachedDeclarations.getFieldForObjectInstance(unitClass.owner)
|
||||
return irCallOp(invokeSuspend.symbol, invokeSuspend.returnType, lambda, irGetField(null, unitField))
|
||||
}
|
||||
private fun IrBlockBodyBuilder.callInvokeSuspend(invokeSuspend: IrSimpleFunction, lambda: IrExpression): IrExpression =
|
||||
irCallOp(invokeSuspend.symbol, invokeSuspend.returnType, lambda, irUnit())
|
||||
|
||||
// Primary constructor accepts parameters equal to function reference arguments + continuation and sets the fields.
|
||||
private fun IrClass.addPrimaryConstructorForLambda(
|
||||
info: SuspendLambdaInfo,
|
||||
fields: List<IrField>,
|
||||
insideInlineFunction: Boolean
|
||||
): IrConstructor =
|
||||
private fun IrClass.addPrimaryConstructorForLambda(superClass: IrClass, arity: Int): IrConstructor =
|
||||
addConstructor {
|
||||
origin = JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA
|
||||
isPrimary = true
|
||||
returnType = defaultType
|
||||
visibility = if (insideInlineFunction) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
}.also { constructor ->
|
||||
for ((param, arg) in info.reference.getArguments()) {
|
||||
constructor.addValueParameter(name = param.name.asString(), type = arg.type)
|
||||
}
|
||||
val completionParameterSymbol = constructor.addCompletionValueParameter()
|
||||
|
||||
val superClass =
|
||||
if (info.isRestricted) context.ir.symbols.restrictedSuspendLambdaClass
|
||||
else context.ir.symbols.suspendLambdaClass
|
||||
val superClassConstructor = superClass.owner.constructors.single {
|
||||
val superClassConstructor = superClass.constructors.single {
|
||||
it.valueParameters.size == 2 && it.valueParameters[0].type.isInt() && it.valueParameters[1].type.isNullableContinuation()
|
||||
}
|
||||
constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
|
||||
+irDelegatingConstructorCall(superClassConstructor).also {
|
||||
it.putValueArgument(0, irInt(info.arity + 1))
|
||||
it.putValueArgument(0, irInt(arity + 1))
|
||||
it.putValueArgument(1, irGet(completionParameterSymbol))
|
||||
}
|
||||
|
||||
for ((index, param) in constructor.valueParameters.dropLast(1).withIndex()) {
|
||||
+irSetField(irGet(thisReceiver!!), fields[index], irGet(param))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,41 +355,43 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
dispatchReceiverParameter: IrValueParameter?,
|
||||
attributeContainer: IrAttributeContainer,
|
||||
capturesCrossinline: Boolean
|
||||
): IrClass {
|
||||
return context.ir.symbols.continuationImplClass.owner
|
||||
.createContinuationClassFor(
|
||||
irFunction,
|
||||
JvmLoweredDeclarationOrigin.CONTINUATION_CLASS,
|
||||
if (capturesCrossinline) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
).apply {
|
||||
copyTypeParametersFrom(irFunction)
|
||||
val resultField = addField {
|
||||
origin = JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD
|
||||
name = Name.identifier(context.state.languageVersionSettings.dataFieldName())
|
||||
type = context.irBuiltIns.anyNType
|
||||
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
val capturedThisField = dispatchReceiverParameter?.let {
|
||||
addField {
|
||||
name = Name.identifier("this$0")
|
||||
type = it.type
|
||||
origin = InnerClassesSupport.FIELD_FOR_OUTER_THIS
|
||||
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
isFinal = true
|
||||
}
|
||||
}
|
||||
val labelField = addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType, JavaDescriptorVisibilities.PACKAGE_VISIBILITY)
|
||||
addConstructorForNamedFunction(capturedThisField, capturesCrossinline)
|
||||
addInvokeSuspendForNamedFunction(
|
||||
irFunction,
|
||||
resultField,
|
||||
labelField,
|
||||
capturedThisField,
|
||||
irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION
|
||||
)
|
||||
copyAttributes(attributeContainer)
|
||||
): IrClass =
|
||||
context.irFactory.buildClass {
|
||||
name = Name.special("<Continuation>")
|
||||
origin = JvmLoweredDeclarationOrigin.CONTINUATION_CLASS
|
||||
visibility = if (capturesCrossinline) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}.apply {
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
superTypes += context.ir.symbols.continuationImplClass.owner.defaultType
|
||||
parent = irFunction
|
||||
|
||||
copyTypeParametersFrom(irFunction)
|
||||
val resultField = addField {
|
||||
origin = JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD
|
||||
name = Name.identifier(context.state.languageVersionSettings.dataFieldName())
|
||||
type = context.irBuiltIns.anyNType
|
||||
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
}
|
||||
val capturedThisField = dispatchReceiverParameter?.let {
|
||||
addField {
|
||||
name = Name.identifier("this$0")
|
||||
type = it.type
|
||||
origin = InnerClassesSupport.FIELD_FOR_OUTER_THIS
|
||||
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
isFinal = true
|
||||
}
|
||||
}
|
||||
val labelField = addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType, JavaDescriptorVisibilities.PACKAGE_VISIBILITY)
|
||||
addConstructorForNamedFunction(capturedThisField, capturesCrossinline)
|
||||
addInvokeSuspendForNamedFunction(
|
||||
irFunction,
|
||||
resultField,
|
||||
labelField,
|
||||
capturedThisField,
|
||||
irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION
|
||||
)
|
||||
copyAttributes(attributeContainer)
|
||||
}
|
||||
|
||||
private fun IrClass.addConstructorForNamedFunction(capturedThisField: IrField?, capturesCrossinline: Boolean): IrConstructor =
|
||||
addConstructor {
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ internal val propertyReferencePhase = makeIrFilePhase(
|
||||
description = "Construct KProperty instances returned by expressions such as A::x and A()::x",
|
||||
// This must be done after contents of functions are extracted into separate classes, or else the `$$delegatedProperties`
|
||||
// field will end up in the wrong class (not the one that declares the delegated property).
|
||||
prerequisite = setOf(functionReferencePhase)
|
||||
prerequisite = setOf(functionReferencePhase, suspendLambdaPhase)
|
||||
)
|
||||
|
||||
internal class PropertyReferenceLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
LineBreakpoint created at coroutine.kt:17
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
|
||||
Reference in New Issue
Block a user