Skip to content

Commit

Permalink
Fix scala#18238: Emit an explicit LineNumber for empty else branches.
Browse files Browse the repository at this point in the history
If we don't, the code generated for the `else` branch remains
associated with the last instruction of the `then` branch, which
yields to confusing debugging sessions.
  • Loading branch information
sjrd committed Jun 26, 2024
1 parent b3f113e commit 04368da
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
if hasElse then
genLoadTo(elsep, expectedType, dest)
else
/* #18238 Re-emit a line number attached to the If, so that the adaptation
* and jump are not associated to the last instruction of the then branch.
*/
lineNumber(tree)
genAdaptAndSendToDest(UNIT, expectedType, dest)
expectedType
end if
Expand Down
88 changes: 88 additions & 0 deletions compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1963,6 +1963,94 @@ class DottyBytecodeTests extends DottyBytecodeTest {
assertSameCode(instructions, expected)
}
}

@Test def i18238a = {
// Test that `LineNumber`s are correct -- variant with an infinite loop
val source =
"""object Main {
| def method(): Int = {
| var x = 3
| var y = 2
|
| while (true) {
| if (x < y) {
| if (x >= y)
| x += 1
| else
| y -= 1
| } // the GOTO in the implicit else branch was still attached to the previous line
| }
|
| 5
| }
|}
""".stripMargin

checkBCode(source) { dir =>
val clsIn = dir.lookupName("Main$.class", directory = false).input
val clsNode = loadClassNode(clsIn, skipDebugInfo = false)
val method = getMethod(clsNode, "method")
val instructions = instructionsFromMethod(method).filter(_.isInstanceOf[LineNumber])

val expected = List(
LineNumber(3, Label(0)),
LineNumber(4, Label(4)),
LineNumber(6, Label(8)),
LineNumber(7, Label(14)),
LineNumber(8, Label(19)),
LineNumber(9, Label(24)),
LineNumber(11, Label(28)),
LineNumber(7, Label(33)), // this line number was missing
LineNumber(15, Label(37)),
)

assertSameCode(instructions, expected)
}
}

@Test def i18238b = {
// Test that `LineNumber`s are correct -- variant with a finite loop
val source =
"""object Main {
| def method(): Int = {
| var x = 3
| var y = 2
|
| while (x > y) {
| if (x < y) {
| if (x >= y)
| x += 1
| else
| y -= 1
| } // the GOTO in the implicit else branch was still attached to the previous line
| }
|
| 5
| }
|}
""".stripMargin

checkBCode(source) { dir =>
val clsIn = dir.lookupName("Main$.class", directory = false).input
val clsNode = loadClassNode(clsIn, skipDebugInfo = false)
val method = getMethod(clsNode, "method")
val instructions = instructionsFromMethod(method).filter(_.isInstanceOf[LineNumber])

val expected = List(
LineNumber(3, Label(0)),
LineNumber(4, Label(4)),
LineNumber(6, Label(8)),
LineNumber(7, Label(14)),
LineNumber(8, Label(19)),
LineNumber(9, Label(24)),
LineNumber(11, Label(28)),
LineNumber(7, Label(33)), // this line number was missing
LineNumber(15, Label(37)),
)

assertSameCode(instructions, expected)
}
}
}

object invocationReceiversTestCode {
Expand Down

0 comments on commit 04368da

Please sign in to comment.