[IR+Tests] Improve Local Function Debugging Experience

This change improves the debugging experience around local functions
on the IR backend. The changes include moving old
checkLocalVariablesTable (cLVT) tests to the new stepping/local variable
infrastructure in order to refine the tests and further define the
behavior of the two JVM backends, and their differences.

The primary ported test case is cLVT/localFun.kt that documents the
discrepancy in implementation strategy for local functions on the two
backends. The old backend implements local functions as lambdas
assigned to a local variable while the IR backend lifts them out as
static funtions on the surrounding class. The discrepancies and their
consequences are documented in bytecodeListing, idea-stepping,
localVariableTable and debugStepping tests.

The only _code change_ is disabling the captured variable name
mangling for captured variables on the IR backend. Captured variables
are passed as arguments to the static function, so in the debugger,
they really just are local variables. For them to show properly in the
debugger and be detectable by evaluate expression, they simply need no
mangling.

Finally, this change cleans 3 redundant cLVT tests, copyFunction.kt
and destructuringInlineLambda.kt and destructuringInFor.kt, that are
all covered in the new suite. The stepping behavior needs to be made
precise around for loops, but that is an entirely seperate issue.
This commit is contained in:
Kristoffer Andersen
2020-12-09 17:15:46 +01:00
committed by max-kammerer
parent c2d7b69e5f
commit 43b61a618d
33 changed files with 324 additions and 127 deletions
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
@@ -633,7 +632,7 @@ class LocalDeclarationsLowering(
newDeclaration.copyAttributes(oldDeclaration)
newDeclaration.valueParameters += createTransformedValueParameters(
capturedValues, localFunctionContext, oldDeclaration, newDeclaration
capturedValues, localFunctionContext, oldDeclaration, newDeclaration, isExplicitLocalFunction = oldDeclaration.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
)
newDeclaration.recordTransformedValueParameters(localFunctionContext)
@@ -646,7 +645,8 @@ class LocalDeclarationsLowering(
capturedValues: List<IrValueSymbol>,
localFunctionContext: LocalContext,
oldDeclaration: IrFunction,
newDeclaration: IrFunction
newDeclaration: IrFunction,
isExplicitLocalFunction: Boolean = false
) = ArrayList<IrValueParameter>(capturedValues.size + oldDeclaration.valueParameters.size).apply {
val generatedNames = mutableSetOf<String>()
capturedValues.mapIndexedTo(this) { i, capturedValue ->
@@ -657,7 +657,7 @@ class LocalDeclarationsLowering(
origin =
if (p is IrValueParameter && p.index < 0 && newDeclaration is IrConstructor) BOUND_RECEIVER_PARAMETER
else BOUND_VALUE_PARAMETER
name = suggestNameForCapturedValue(p, generatedNames)
name = suggestNameForCapturedValue(p, generatedNames, isExplicitLocalFunction = isExplicitLocalFunction)
index = i
type = localFunctionContext.remapType(p.type)
isCrossInline = (capturedValue as? IrValueParameterSymbol)?.owner?.isCrossinline == true
@@ -786,7 +786,7 @@ class LocalDeclarationsLowering(
private fun Name.stripSpecialMarkers(): String =
if (isSpecial) asString().substring(1, asString().length - 1) else asString()
private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, usedNames: MutableSet<String>): Name {
private fun suggestNameForCapturedValue(declaration: IrValueDeclaration, usedNames: MutableSet<String>, isExplicitLocalFunction: Boolean = false): Name {
if (declaration is IrValueParameter) {
if (declaration.name.asString() == "<this>" && declaration.isDispatchReceiver()) {
return findFirstUnusedName("this\$0", usedNames) {
@@ -804,12 +804,21 @@ class LocalDeclarationsLowering(
}
}
}
val base = if (declaration.name.isSpecial)
val base = if (declaration.name.isSpecial) {
declaration.name.stripSpecialMarkers()
else
} else {
declaration.name.asString()
return findFirstUnusedName(base.synthesizedString, usedNames) {
"$base$$it".synthesizedString
}
return if (isExplicitLocalFunction && declaration is IrVariable) {
findFirstUnusedName(base, usedNames) {
"$base$$it"
}
} else {
findFirstUnusedName(base.synthesizedString, usedNames) {
"$base$$it".synthesizedString
}
}
}
@@ -1,6 +0,0 @@
data class someClass(val a: Double, val b: Double)
// METHOD : someClass.copy(DD)LsomeClass;
// VARIABLE : NAME=this TYPE=LsomeClass; INDEX=0
// VARIABLE : NAME=a TYPE=D INDEX=1
// VARIABLE : NAME=b TYPE=D INDEX=3
@@ -1,14 +0,0 @@
// WITH_RUNTIME
fun box() {
val map: Map<String, String> = mapOf()
for ((a, b) in map) {
a + b
}
}
// METHOD : DestructuringInForKt.box()V
// VARIABLE : NAME=b TYPE=Ljava/lang/String; INDEX=4
// VARIABLE : NAME=a TYPE=Ljava/lang/String; INDEX=3
// VARIABLE : NAME=map TYPE=Ljava/util/Map; INDEX=0
@@ -1,22 +0,0 @@
inline fun foo(x: (Int, Station) -> Unit) {
x(1, Station(null, "", 1))
}
data class Station(
val id: String?,
val name: String,
val distance: Int)
fun box(): String {
foo { i, (a1, a2, a3) -> i + a3 }
return "OK"
}
// METHOD : DestructuringInlineLambdaKt.box()Ljava/lang/String;
// VARIABLE : NAME=a1 TYPE=Ljava/lang/String; INDEX=4
// VARIABLE : NAME=a2 TYPE=Ljava/lang/String; INDEX=5
// VARIABLE : NAME=a3 TYPE=I INDEX=6
// VARIABLE : NAME=i TYPE=I INDEX=2
// VARIABLE : NAME=$dstr$a1$a2$a3 TYPE=LStation; INDEX=1
// VARIABLE : NAME=$i$a$-foo-DestructuringInlineLambdaKt$box$1 TYPE=I INDEX=3
// VARIABLE : NAME=$i$f$foo TYPE=I INDEX=0
-18
View File
@@ -1,18 +0,0 @@
fun foo() {
val x = 1
fun bar() {
val y = x
}
}
// Local function bodies are in a separate class (implementing FunctionN) for non-IR, and are static methods in the enclosing class for IR.
// JVM_TEMPLATES
// METHOD : LocalFunKt$foo$1.invoke()V
// VARIABLE : NAME=y TYPE=I INDEX=1
// VARIABLE : NAME=this TYPE=LLocalFunKt$foo$1; INDEX=0
// JVM_IR_TEMPLATES
// METHOD : LocalFunKt.foo$bar(I)V
// VARIABLE : NAME=y TYPE=I INDEX=1
// VARIABLE : NAME=$x TYPE=I INDEX=0
@@ -0,0 +1,5 @@
fun foo() {
fun bar() {
}
}
@@ -0,0 +1,18 @@
@kotlin.Metadata
final class LocalFunctionKt$foo$1 {
// source: 'localFunction.kt'
enclosing method LocalFunctionKt.foo()V
public final static field INSTANCE: LocalFunctionKt$foo$1
inner (anonymous) class LocalFunctionKt$foo$1
static method <clinit>(): void
method <init>(): void
public synthetic bridge method invoke(): java.lang.Object
public final method invoke(): void
}
@kotlin.Metadata
public final class LocalFunctionKt {
// source: 'localFunction.kt'
inner (anonymous) class LocalFunctionKt$foo$1
public final static method foo(): void
}
@@ -0,0 +1,6 @@
@kotlin.Metadata
public final class LocalFunctionKt {
// source: 'localFunction.kt'
private final static method foo$bar(): void
public final static method foo(): void
}
@@ -1,19 +1,16 @@
//FILE: test.kt
// WITH_RUNTIME
fun box() {
val map: Map<String, String> = mapOf("1" to "23")
for ((a, b)
in map) {
for ((a, b) in map) {
a + b
}
}
// IGNORE_BACKEND: JVM_IR
// LOCAL VARIABLES
// test.kt:6 box:
// test.kt:8 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:9 box: map:java.util.Map=java.util.Collections$SingletonMap, a:java.lang.String="1":java.lang.String, b:java.lang.String="23":java.lang.String
// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:11 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:5 box:
// test.kt:6 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:7 box: map:java.util.Map=java.util.Collections$SingletonMap, a:java.lang.String="1":java.lang.String, b:java.lang.String="23":java.lang.String
// test.kt:6 box: map:java.util.Map=java.util.Collections$SingletonMap
// test.kt:9 box: map:java.util.Map=java.util.Collections$SingletonMap
+13
View File
@@ -0,0 +1,13 @@
// FILE: test.kt
fun foo() {}
fun box() {
foo()
}
// LOCAL VARIABLES
// test.kt:7 box:
// test.kt:4 foo:
// test.kt:8 box:
+44 -6
View File
@@ -1,16 +1,54 @@
//FILE: test.kt
//FILE: test.kt
fun foo() {
val x = 1
fun bar() {
val y = x
}
bar()
}
fun box() {
foo()
}
// IGNORE_BACKEND: JVM_IR
// Local functions are compiled to private static functions on the class
// containing the local funtion. This has a number of consequences observable
// from a debugging perspective, for this test specifically:
// - local functions do not figure in the LVT of the outer function, as they
// are not instantiated.
// - the _declaration_ of the local function does not figure in the byte code
// of the outer function and hence, has no line number
// - captures are treated differently, according to the implementation
// strategy: on the IR, captures are passed as arguments to the static
// function, on the old backend, they are added to fields on the lambda
// object. Hence, for debugging purposes, captures are "just"
// variables local to the function, and hence need no name mangling to
// properly figure in the debugger.
// LOCAL VARIABLES
// test.kt:9 box:
// test.kt:4 foo:
// test.kt:6 foo: $fun$bar$1:TestKt$foo$1=TestKt$foo$1
// test.kt:10 box:
// test.kt:13 box:
// test.kt:5 foo:
// LOCAL VARIABLES JVM
// test.kt:6 foo: x:int=1:int
// LOCAL VARIABLES JVM
// test.kt:9 foo: x:int=1:int, $fun$bar$1:TestKt$foo$1=TestKt$foo$1
// LOCAL VARIABLES JVM_IR
// test.kt:9 foo: x:int=1:int
// LOCAL VARIABLES JVM
// test.kt:7 invoke:
// test.kt:8 invoke: y:int=1:int
// LOCAL VARIABLES JVM_IR
// test.kt:7 foo$bar: x:int=1:int
// test.kt:8 foo$bar: x:int=1:int, y:int=1:int
// LOCAL VARIABLES JVM
// test.kt:10 foo: x:int=1:int, $fun$bar$1:TestKt$foo$1=TestKt$foo$1
// test.kt:14 box:
// LOCAL VARIABLES JVM_IR
// test.kt:10 foo: x:int=1:int
// test.kt:14 box:
@@ -0,0 +1,31 @@
//FILE: test.kt
fun foo() {
fun bar() {
}
}
fun box() {
foo()
}
// Local functions are compiled to private static functions on the class
// containing the local funtion. This has a number of consequences observable
// from a debugging perspective, for this test specically:
// - local functions do not figure in the LVT of the outer function, as they
// are not instantiated.
// - the _declaration_ of the local function does not figure in the byte code
// of the outer function and hence, has no line number
// LOCAL VARIABLES
// LOCAL VARIABLES JVM
// test.kt:10 box:
// test.kt:5 foo:
// test.kt:7 foo: $fun$bar$1:TestKt$foo$1=TestKt$foo$1
// test.kt:11 box:
// LOCAL VARIABLES JVM_IR
// test.kt:10 box:
// test.kt:7 foo:
// test.kt:11 box:
@@ -0,0 +1,25 @@
// FILE: test.kt
fun box() {
"OK"
fun bar() = "OK"
"OK"
bar()
"OK"
}
// LINENUMBERS
// test.kt:4 box
// LINENUMBERS JVM
// test.kt:5 box
// LINENUMBERS
// test.kt:6 box
// test.kt:7 box
// LINENUMBERS JVM
// test.kt:5 invoke
// LINENUMBERS JVM_IR
// test.kt:5 box$bar
// LINENUMBERS
// test.kt:7 box
// test.kt:8 box
// test.kt:9 box
@@ -155,6 +155,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/kt43519.kt");
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunction.kt");
}
@TestMetadata("localFunctionInInitBlock.kt")
public void testLocalFunctionInInitBlock() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
@@ -30,26 +30,11 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("copyFunction.kt")
public void testCopyFunction() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt");
}
@TestMetadata("destructuringInFor.kt")
public void testDestructuringInFor() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInFor.kt");
}
@TestMetadata("destructuringInLambdas.kt")
public void testDestructuringInLambdas() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt");
}
@TestMetadata("destructuringInlineLambda.kt")
public void testDestructuringInlineLambda() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt");
}
@TestMetadata("inlineLambdaWithItParam.kt")
public void testInlineLambdaWithItParam() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt");
@@ -90,11 +75,6 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar
runTest("compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt");
}
@TestMetadata("localFun.kt")
public void testLocalFun() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/localFun.kt");
}
@TestMetadata("objectInLocalPropertyDelegate.kt")
public void testObjectInLocalPropertyDelegate() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/objectInLocalPropertyDelegate.kt");
@@ -56,6 +56,12 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest {
runTest("compiler/testData/debug/localVariables/destructuringInLambdas.kt");
}
@Test
@TestMetadata("emptyFun.kt")
public void testEmptyFun() throws Exception {
runTest("compiler/testData/debug/localVariables/emptyFun.kt");
}
@Test
@TestMetadata("inlineProperty.kt")
public void testInlineProperty() throws Exception {
@@ -74,6 +80,12 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest {
runTest("compiler/testData/debug/localVariables/localFun.kt");
}
@Test
@TestMetadata("localFunUnused.kt")
public void testLocalFunUnused() throws Exception {
runTest("compiler/testData/debug/localVariables/localFunUnused.kt");
}
@Test
@TestMetadata("underscoreNames.kt")
public void testUnderscoreNames() throws Exception {
@@ -266,6 +266,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
runTest("compiler/testData/debug/stepping/localFunction.kt");
}
@Test
@TestMetadata("localFunctionWIthOnelineExpressionBody.kt")
public void testLocalFunctionWIthOnelineExpressionBody() throws Exception {
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
}
@Test
@TestMetadata("multilineFunctionCall.kt")
public void testMultilineFunctionCall() throws Exception {
@@ -56,6 +56,12 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest {
runTest("compiler/testData/debug/localVariables/destructuringInLambdas.kt");
}
@Test
@TestMetadata("emptyFun.kt")
public void testEmptyFun() throws Exception {
runTest("compiler/testData/debug/localVariables/emptyFun.kt");
}
@Test
@TestMetadata("inlineProperty.kt")
public void testInlineProperty() throws Exception {
@@ -74,6 +80,12 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest {
runTest("compiler/testData/debug/localVariables/localFun.kt");
}
@Test
@TestMetadata("localFunUnused.kt")
public void testLocalFunUnused() throws Exception {
runTest("compiler/testData/debug/localVariables/localFunUnused.kt");
}
@Test
@TestMetadata("underscoreNames.kt")
public void testUnderscoreNames() throws Exception {
@@ -266,6 +266,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
runTest("compiler/testData/debug/stepping/localFunction.kt");
}
@Test
@TestMetadata("localFunctionWIthOnelineExpressionBody.kt")
public void testLocalFunctionWIthOnelineExpressionBody() throws Exception {
runTest("compiler/testData/debug/stepping/localFunctionWIthOnelineExpressionBody.kt");
}
@Test
@TestMetadata("multilineFunctionCall.kt")
public void testMultilineFunctionCall() throws Exception {
@@ -155,6 +155,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/kt43519.kt");
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunction.kt");
}
@TestMetadata("localFunctionInInitBlock.kt")
public void testLocalFunctionInInitBlock() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
@@ -30,26 +30,11 @@ public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLoca
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("copyFunction.kt")
public void testCopyFunction() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt");
}
@TestMetadata("destructuringInFor.kt")
public void testDestructuringInFor() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInFor.kt");
}
@TestMetadata("destructuringInLambdas.kt")
public void testDestructuringInLambdas() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInLambdas.kt");
}
@TestMetadata("destructuringInlineLambda.kt")
public void testDestructuringInlineLambda() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/destructuringInlineLambda.kt");
}
@TestMetadata("inlineLambdaWithItParam.kt")
public void testInlineLambdaWithItParam() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt");
@@ -90,11 +75,6 @@ public class IrCheckLocalVariablesTableTestGenerated extends AbstractIrCheckLoca
runTest("compiler/testData/checkLocalVariablesTable/lambdaAsVar.kt");
}
@TestMetadata("localFun.kt")
public void testLocalFun() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/localFun.kt");
}
@TestMetadata("objectInLocalPropertyDelegate.kt")
public void testObjectInLocalPropertyDelegate() throws Exception {
runTest("compiler/testData/checkLocalVariablesTable/objectInLocalPropertyDelegate.kt");
@@ -337,6 +337,11 @@ public class IrKotlinEvaluateExpressionTestGenerated extends AbstractIrKotlinEva
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localClass.kt");
}
@TestMetadata("localFunctionCapturedLocalVariable.kt")
public void testLocalFunctionCapturedLocalVariable() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt");
}
@TestMetadata("localFunctionsWithReceivers.kt")
public void testLocalFunctionsWithReceivers() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionsWithReceivers.kt");
@@ -503,6 +503,16 @@ public class IrKotlinSteppingTestGenerated extends AbstractIrKotlinSteppingTest
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt");
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt");
}
@TestMetadata("localFunctionWithSingleLineExpressionBody.kt")
public void testLocalFunctionWithSingleLineExpressionBody() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt");
}
@TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt")
public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt");
@@ -336,6 +336,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localClass.kt");
}
@TestMetadata("localFunctionCapturedLocalVariable.kt")
public void testLocalFunctionCapturedLocalVariable() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionCapturedLocalVariable.kt");
}
@TestMetadata("localFunctionsWithReceivers.kt")
public void testLocalFunctionsWithReceivers() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/evaluation/singleBreakpoint/localFunctionsWithReceivers.kt");
@@ -503,6 +503,16 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt");
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunction.kt");
}
@TestMetadata("localFunctionWithSingleLineExpressionBody.kt")
public void testLocalFunctionWithSingleLineExpressionBody() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/localFunctionWithSingleLineExpressionBody.kt");
}
@TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt")
public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt");
@@ -0,0 +1,13 @@
package localFunctionCapturedLocalVariable
fun main(args: Array<String>) {
val a = 1
fun local() {
//Breakpoint!
val x = a + 2
}
local()
}
// EXPRESSION: a
// RESULT: 1: I
@@ -0,0 +1,8 @@
LineBreakpoint created at localFunctionCapturedLocalVariable.kt:7
Run Java
Connected to the target VM
localFunctionCapturedLocalVariable.kt:7
Compile bytecode for a
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,6 @@
LineBreakpoint created at localFunction.kt:5
Run Java
Connected to the target VM
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,12 @@
package localFunction
fun main() {
//Breakpoint!
fun bar() {
"OK"
}
bar()
}
// STEP_OVER: 1
// Code compiled on the IR cannot break on local function declarations
@@ -0,0 +1,8 @@
LineBreakpoint created at localFunction.kt:5
Run Java
Connected to the target VM
localFunction.kt:5
localFunction.kt:8
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,9 @@
LineBreakpoint created at localFunctionWithSingleLineExpressionBody.kt:5
Run Java
Connected to the target VM
localFunctionWithSingleLineExpressionBody.kt:5
localFunctionWithSingleLineExpressionBody.kt:7
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,13 @@
package localFunctionWithSingleLineExpressionBody
fun main() {
//Breakpoint!
fun bar() = "OK"
val x = 1
bar()
}
// STEP_OVER: 1
// The behavior of the two backends is different because they stop at two different instructions.
// - The JVM backend stops on the declaration of bar on main:5, so stepping over proceeds to main:6
// - The IR backend stops on the _body_ of bar when called from main:7, so proceeds to main:7
@@ -0,0 +1,10 @@
LineBreakpoint created at localFunctionWithSingleLineExpressionBody.kt:5
Run Java
Connected to the target VM
localFunctionWithSingleLineExpressionBody.kt:5
localFunctionWithSingleLineExpressionBody.kt:6
resuming localFunctionWithSingleLineExpressionBody.kt:5
Disconnected from the target VM
Process finished with exit code 0