From 8a5f260d044b6891297824f606b95b32a495c696 Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Tue, 24 Nov 2020 12:53:16 +0100 Subject: [PATCH] [IR] Align debugging of suspend lambdas with old BE The existing backend restores LVs and parameters from the suspend lambda fields used for spilling between suspension points, hence they are visible in the debugger as local variables, plain and simple. This PR introduces the same pattern to the IR backend, to bring the debugging experience in line with the existing backend. Both backends are still at the mercy of the liveness analysis performed in the coroutine transformer where a liveness analysis minimizes live ranges of entries in the LVT. E.g. an unused parameter will be dropped entirely. Adjusted existing test expectations accounting for the differences in LV behavior. --- .../jvm/lower/SuspendLambdaLowering.kt | 51 ++++++++++++------- .../parametersInSuspendLambda/dataClass.kt | 11 ---- .../extensionComponents.kt | 5 +- .../parametersInSuspendLambda/generic.kt | 13 +---- .../otherParameters.kt | 11 ---- .../parametersInSuspendLambda/parameters.kt | 16 +++--- .../debug/localVariableCorrectLabel.kt | 8 ++- .../localVariables/suspend/underscoreNames.kt | 15 ++---- ...KotlinEvaluateExpressionTestGenerated.java | 5 ++ ...KotlinEvaluateExpressionTestGenerated.java | 5 ++ .../coroutines/capturedReceiverName.kt | 40 +++++++++++++++ .../coroutines/capturedReceiverName.out | 10 ++++ 12 files changed, 112 insertions(+), 78 deletions(-) create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.out diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt index a634a30136f..b9c7b3ab7d7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt @@ -5,12 +5,10 @@ package org.jetbrains.kotlin.backend.jvm.lower +import com.intellij.lang.jvm.source.JvmDeclarationSearch import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext -import org.jetbrains.kotlin.backend.common.ir.copyTo -import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor -import org.jetbrains.kotlin.backend.common.ir.isSuspend -import org.jetbrains.kotlin.backend.common.ir.moveBodyTo +import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase @@ -29,12 +27,12 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -43,6 +41,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin internal val suspendLambdaPhase = makeIrFilePhase( ::SuspendLambdaLowering, @@ -191,7 +190,7 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin } val invokeSuspend = addInvokeSuspendForLambda(function, suspendLambda, parametersFields) if (function.capturesCrossinline()) { - addInvokeSuspendForInlineForLambda(invokeSuspend) + addInvokeSuspendForInlineLambda(invokeSuspend) } if (createToOverride != null) { addInvokeCallingCreate(addCreate(constructor, createToOverride, parametersFields), invokeSuspend, invokeToOverride) @@ -209,19 +208,37 @@ private class SuspendLambdaLowering(context: JvmBackendContext) : SuspendLowerin it.valueParameters[0].type.isKotlinResult() } return addFunctionOverride(superMethod, irFunction.startOffset, irFunction.endOffset).apply { - body = irFunction.moveBodyTo(this, mapOf())?.transform(object : IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - val parameter = (expression.symbol.owner as? IrValueParameter)?.takeIf { it.parent == irFunction } - ?: return expression - val field = fields[parameter.index + if (irFunction.extensionReceiverParameter != null) 1 else 0] + val localVals: List = fields.mapIndexed { index, field -> + buildVariable( + parent = this, + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.DEFINED, + name = field.name, + type = field.type + ).apply { val receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter!!.symbol) - return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type, receiver) + val initializerBlock = IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.type) + initializerBlock.statements += IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.symbol, field.type, receiver) + initializer = initializerBlock } - }, null) + } + + body = irFunction.moveBodyTo(this, mapOf())?.let { body -> + body.transform(object : IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + val parameter = (expression.symbol.owner as? IrValueParameter)?.takeIf { it.parent == irFunction } + ?: return expression + val lvar = localVals[parameter.index + if (irFunction.extensionReceiverParameter != null) 1 else 0] + return IrGetValueImpl(expression.startOffset, expression.endOffset, lvar.symbol) + } + }, null) + context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, localVals + body.statements) + } } } - private fun IrClass.addInvokeSuspendForInlineForLambda(invokeSuspend: IrSimpleFunction): IrSimpleFunction { + private fun IrClass.addInvokeSuspendForInlineLambda(invokeSuspend: IrSimpleFunction): IrSimpleFunction { return addFunction( INVOKE_SUSPEND_METHOD_NAME + FOR_INLINE_SUFFIX, context.irBuiltIns.anyNType, diff --git a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/dataClass.kt b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/dataClass.kt index 55270f96d5d..b4e53b487cf 100644 --- a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/dataClass.kt +++ b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/dataClass.kt @@ -11,21 +11,10 @@ suspend fun foo(data: Data, body: suspend (Data) -> Unit) { body(data) } -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. - // METHOD : DataClassKt$test$2.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; -// JVM_TEMPLATES // VARIABLE : NAME=$dstr$x_param$y_param TYPE=LData; INDEX=2 // VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=3 // VARIABLE : NAME=y_param TYPE=I INDEX=4 // VARIABLE : NAME=this TYPE=LDataClassKt$test$2; INDEX=0 // VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 - -// JVM_IR_TEMPLATES -// VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=2 -// VARIABLE : NAME=y_param TYPE=I INDEX=3 -// VARIABLE : NAME=this TYPE=LDataClassKt$test$2; INDEX=0 -// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 diff --git a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/extensionComponents.kt b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/extensionComponents.kt index 329c7a95838..0b83d31d4af 100644 --- a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/extensionComponents.kt +++ b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/extensionComponents.kt @@ -22,10 +22,6 @@ suspend fun test() = B.bar() // Local function bodies (i.e., `A.component3()`) are in a separate class (implementing FunctionN) for non-IR, and are static methods // in the enclosing class for IR. Therefore the ordinal in the suspend lambda class name is different for non-IR (`$3`) vs IR (e.g., `$2`). // -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. - // JVM_TEMPLATES // METHOD : ExtensionComponentsKt$bar$3.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; // VARIABLE : NAME=$dstr$x_param$y_param$z_param TYPE=LA; INDEX=2 @@ -37,6 +33,7 @@ suspend fun test() = B.bar() // JVM_IR_TEMPLATES // METHOD : ExtensionComponentsKt$bar$2.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; +// VARIABLE : NAME=$dstr$x_param$y_param$z_param TYPE=LA; INDEX=2 // VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=2 // VARIABLE : NAME=y_param TYPE=Ljava/lang/String; INDEX=3 // VARIABLE : NAME=z_param TYPE=I INDEX=4 diff --git a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/generic.kt b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/generic.kt index 128ad21f6ba..506636165ed 100644 --- a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/generic.kt +++ b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/generic.kt @@ -8,21 +8,10 @@ suspend fun test() = foo(A("OK", 1)) { (x_param, y_param) -> x_param + (y_param.toString()) } -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. - // METHOD : GenericKt$test$2.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; -// JVM_TEMPLATES // VARIABLE : NAME=$dstr$x_param$y_param TYPE=LA; INDEX=2 // VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=3 // VARIABLE : NAME=y_param TYPE=I INDEX=4 // VARIABLE : NAME=this TYPE=LGenericKt$test$2; INDEX=0 -// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 - -// JVM_IR_TEMPLATES -// VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=2 -// VARIABLE : NAME=y_param TYPE=I INDEX=3 -// VARIABLE : NAME=this TYPE=LGenericKt$test$2; INDEX=0 -// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 +// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 \ No newline at end of file diff --git a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/otherParameters.kt b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/otherParameters.kt index 6e9909a9254..94e6de609fa 100644 --- a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/otherParameters.kt +++ b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/otherParameters.kt @@ -7,13 +7,8 @@ suspend fun test() = foo(A("O", "K")) { i_param, (x_param, y_param), v_param -> i_param.toString() + x_param + y_param + v_param } -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. - // METHOD : OtherParametersKt$test$2.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; -// JVM_TEMPLATES // VARIABLE : NAME=i_param TYPE=I INDEX=2 // VARIABLE : NAME=$dstr$x_param$y_param TYPE=LA; INDEX=3 // VARIABLE : NAME=v_param TYPE=Ljava/lang/String; INDEX=4 @@ -21,9 +16,3 @@ suspend fun test() = foo(A("O", "K")) { i_param, (x_param, y_param), v_param -> // VARIABLE : NAME=y_param TYPE=Ljava/lang/String; INDEX=6 // VARIABLE : NAME=this TYPE=LOtherParametersKt$test$2; INDEX=0 // VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 - -// JVM_IR_TEMPLATES -// VARIABLE : NAME=x_param TYPE=Ljava/lang/String; INDEX=2 -// VARIABLE : NAME=y_param TYPE=Ljava/lang/String; INDEX=3 -// VARIABLE : NAME=this TYPE=LOtherParametersKt$test$2; INDEX=0 -// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 diff --git a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/parameters.kt b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/parameters.kt index 3572a208fe1..964126eeb98 100644 --- a/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/parameters.kt +++ b/compiler/testData/checkLocalVariablesTable/parametersInSuspendLambda/parameters.kt @@ -11,9 +11,7 @@ suspend fun foo(data: Data, body: suspend Long.(String, Data, Int) -> Unit) { 1L.body("OK", data, 1) } -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. +// The JVM and IR backend differ in naming scheme of captured receiver paramters in suspend lambdas // METHOD : ParametersKt$test$2.invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; @@ -28,7 +26,11 @@ suspend fun foo(data: Data, body: suspend Long.(String, Data, Int) -> Unit) { // VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 // JVM_IR_TEMPLATES -// VARIABLE : NAME=x TYPE=Ljava/lang/String; INDEX=2 -// VARIABLE : NAME=z TYPE=I INDEX=3 -// VARIABLE : NAME=this TYPE=LParametersKt$test$2; INDEX=0 -// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=1 +// VARIABLE : NAME=$dstr$x$_u24__u24$z TYPE=LData; INDEX=* +// VARIABLE : NAME=$result TYPE=Ljava/lang/Object; INDEX=* +// VARIABLE : NAME=i TYPE=I INDEX=* +// VARIABLE : NAME=p$ TYPE=J INDEX=* +// VARIABLE : NAME=str TYPE=Ljava/lang/String; INDEX=* +// VARIABLE : NAME=this TYPE=LParametersKt$test$2; INDEX=* +// VARIABLE : NAME=x TYPE=Ljava/lang/String; INDEX=* +// VARIABLE : NAME=z TYPE=I INDEX=* \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt b/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt index cb2b95ee703..b10d4d2438d 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/debug/localVariableCorrectLabel.kt @@ -14,14 +14,12 @@ fun main(args: Array) { @BuilderInference suspend fun SequenceScope.awaitSeq(): Int = 42 -// label numbers differ in BEs -// JVM_TEMPLATES // 1 LOCALVARIABLE a I L[0-9]+ L18 -// 1 LINENUMBER 9 L19 /* TODO: JVM_IR does not generate LINENUMBER at the end of the lambda */ -// JVM_IR_TEMPLATES -// 1 LOCALVARIABLE a I L[0-9]+ L16 +// JVM_TEMPLATES +// 1 LINENUMBER 9 L19 + // IGNORE_BACKEND_FIR: JVM_IR diff --git a/compiler/testData/debug/localVariables/suspend/underscoreNames.kt b/compiler/testData/debug/localVariables/suspend/underscoreNames.kt index 728452ff7c3..1fc7379a13e 100644 --- a/compiler/testData/debug/localVariables/suspend/underscoreNames.kt +++ b/compiler/testData/debug/localVariables/suspend/underscoreNames.kt @@ -13,13 +13,8 @@ suspend fun box() = foo(A()) { (x_param, _, y_param) -> x_param + y_param } -// Parameters (including anonymous destructuring parameters) are moved to fields in the Continuation class for the suspend lambda class. -// However, in non-IR, the fields are first stored in local variables, and they are not read directly (even for destructuring components). -// In IR, the fields are directly read from. +// TODO: The backends disagree on the local variables in invoke/invokeSuspend methods -// The local variable for destructuring suspend lambda arguments, in this case -// `$dstr$x_param$_u24__u24$y_param`, is moved to a field in the IR backend, -// so does not figure in the LVT. // LOCAL VARIABLES // test.kt:12 box: $completion:kotlin.coroutines.Continuation=helpers.ResultContinuation @@ -41,16 +36,14 @@ suspend fun box() = foo(A()) { (x_param, _, y_param) -> // LOCAL VARIABLES // test.kt:12 invokeSuspend: // test.kt:5 component1: +// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A +// test.kt:7 component3: // LOCAL VARIABLES JVM // test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A -// test.kt:7 component3: -// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A // LOCAL VARIABLES JVM_IR -// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit -// test.kt:7 component3: -// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, x_param:java.lang.String="O":java.lang.String +// test.kt:12 invokeSuspend: $result:java.lang.Object=kotlin.Unit, $dstr$x_param$_u24__u24$y_param:A=A, x_param:java.lang.String="O":java.lang.String // LOCAL VARIABLES // test.kt:13 invokeSuspend: $result:java.lang.Object=kotlin.Unit, x_param:java.lang.String="O":java.lang.String, y_param:java.lang.String="K":java.lang.String diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java index 00163b02c65..8b7ec2a5965 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/IrKotlinEvaluateExpressionTestGenerated.java @@ -606,6 +606,11 @@ public class IrKotlinEvaluateExpressionTestGenerated extends AbstractIrKotlinEva runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/anyUpdateVariable.kt"); } + @TestMetadata("capturedReceiverName.kt") + public void testCapturedReceiverName() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt"); + } + @TestMetadata("primitivesCoertion.kt") public void testPrimitivesCoertion() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/primitivesCoertion.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java index 075e1da6b92..56165e49bf9 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinEvaluateExpressionTestGenerated.java @@ -605,6 +605,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/anyUpdateVariable.kt"); } + @TestMetadata("capturedReceiverName.kt") + public void testCapturedReceiverName() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt"); + } + @TestMetadata("primitivesCoertion.kt") public void testPrimitivesCoertion() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/primitivesCoertion.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt new file mode 100644 index 00000000000..a6b90312804 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.kt @@ -0,0 +1,40 @@ +package capturedReceiverName + +import kotlin.sequences.* +import kotlin.coroutines.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(object : Continuation{ + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resumeWith(result: Result) { + result.getOrThrow() + } + }) +} + +fun main(args: Array) { + builder { + var s = "OK" + s = strChanger(s) { character -> + //Breakpoint! + character != 'a' // (2) + } + println(s) + } +} + +suspend fun strChanger(str: String, pred: suspend (Char) -> Boolean): String { + var result = "" + str.forEach { + if (pred(it)) { + result += it + } + } + return result +} + +// EXPRESSION: character +// RESULT: 79: C +// 79.toChar() == 'O' \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.out b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.out new file mode 100644 index 00000000000..4370c48eaf0 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/coroutines/capturedReceiverName.out @@ -0,0 +1,10 @@ +LineBreakpoint created at capturedReceiverName.kt:22 +Run Java +Connected to the target VM +capturedReceiverName.kt:22 +Compile bytecode for character +capturedReceiverName.kt:22 +Disconnected from the target VM + +Process finished with exit code 0 +OK