From 05c856f1f771008cce3d564de74a7b11aab6b4a9 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 25 Sep 2020 16:12:17 +0200 Subject: [PATCH] JVM_IR: move SuspendLambdaLowering next to FunctionReferenceLowering #KT-42253 Fixed #KT-39434 Fixed --- .../kotlin/backend/common/ir/IrInlineUtils.kt | 4 +- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 3 +- .../jvm/lower/AddContinuationLowering.kt | 352 +++++++----------- .../jvm/lower/PropertyReferenceLowering.kt | 2 +- .../testData/stepping/custom/coroutine.out | 1 - 5 files changed, 145 insertions(+), 217 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt index 114cec26844..6cae37eac86 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt @@ -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) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index b5b3eb42545..5e0ad2ab2ce 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -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, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index a723400d8e2..7886864fcd1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -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("") - 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>() - val suspendLambdas = mutableMapOf() - 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() + }, 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, - receiverField: IrField? - ): IrSimpleFunction { + private fun IrClass.addInvokeSuspendForLambda(irFunction: IrFunction, fields: List): 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, fieldsForUnbound: List ) = 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, fieldsForUnbound: List ) = 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, fieldsForUnbound: List ): 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, - 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("") + 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 { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index a6d62b1011a..39dc92ed581 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -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 { diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/custom/coroutine.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/custom/coroutine.out index 12eee7b6699..9f9a0963e9f 100644 --- a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/custom/coroutine.out +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/custom/coroutine.out @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR LineBreakpoint created at coroutine.kt:17 Run Java Connected to the target VM