Skip to content

Commit 1ce0885

Browse files
Merge pull request #8754 from dotty-staging/local-var-table
Fix start of local var visibility in classfiles
2 parents 1516b06 + 00d893c commit 1ce0885

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
271271
val Local(tk, _, idx, isSynth) = loc
272272
if (rhs == EmptyTree) { emitZeroOf(tk) }
273273
else { genLoad(rhs, tk) }
274-
val localVarStart = currProgramPoint()
275274
bc.store(idx, tk)
275+
val localVarStart = currProgramPoint()
276276
if (!isSynth) { // there are case <synthetic> ValDef's emitted by patmat
277277
varsInScope ::= (sym -> localVarStart)
278278
}

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import asm.tree._
99

1010
import scala.tools.asm.Opcodes
1111
import scala.jdk.CollectionConverters._
12-
12+
import Opcodes._
1313

1414
class TestBCode extends DottyBytecodeTest {
1515
import ASMConverters._
@@ -786,6 +786,42 @@ class TestBCode extends DottyBytecodeTest {
786786
}
787787
}
788788

789+
790+
@Test // wrong local variable table for methods containing while loops
791+
def t9179(): Unit = {
792+
val code =
793+
"""class C {
794+
| def t(): Unit = {
795+
| var x = ""
796+
| while (x != null) {
797+
| foo()
798+
| x = null
799+
| }
800+
| bar()
801+
| }
802+
| def foo(): Unit = ()
803+
| def bar(): Unit = ()
804+
|}
805+
""".stripMargin
806+
checkBCode(code) { dir =>
807+
val c = loadClassNode(dir.lookupName("C.class", directory = false).input, skipDebugInfo = false)
808+
val t = getMethod(c, "t")
809+
val instructions = instructionsFromMethod(t)
810+
val isFrameLine = (x: Instruction) => x.isInstanceOf[FrameEntry] || x.isInstanceOf[LineNumber]
811+
// TODO: The same test in scalac uses different labels because their LineNumberTable isn't the same as ours,
812+
// this should be investigated.
813+
assertSameCode(instructions.filterNot(isFrameLine), List(
814+
Label(0), Ldc(LDC, ""), VarOp(ASTORE, 1),
815+
Label(5), VarOp(ALOAD, 1), Jump(IFNULL, Label(19)),
816+
Label(10), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "foo", "()V", false), Label(14), Op(ACONST_NULL), VarOp(ASTORE, 1), Jump(GOTO, Label(5)),
817+
Label(19), VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "bar", "()V", false), Label(24), Op(RETURN), Label(26)))
818+
val labels = instructions collect { case l: Label => l }
819+
val x = convertMethod(t).localVars.find(_.name == "x").get
820+
assertEquals(x.start, labels(1))
821+
assertEquals(x.end, labels(5))
822+
}
823+
}
824+
789825
@Test
790826
def invocationReceivers(): Unit = {
791827
import Opcodes._

0 commit comments

Comments
 (0)