The backend of the compiler encodes all Scala definitions into erased Java definitions. It also introduces intermediate methods that we cannot see directly in the source file.
The debugger allows to view the call stack of a program. For the reason exposed above the call stacks contain encoded names that are hard to interpret.
The goal of the project is to show a better call stack by decoding back all the symbols and hiding some intermediate methods.
Example 1: top level definition and encoded operator
@main def run(): Unit = !!
def !! : Unit = println("!!")
example$package$ is the encoded name of the package example
$bang$bang is the encoded name of the method !!
The better call-stack should be:
example.!!()
example.run()
Example 2: private method accessed by inner class
package example
@main def run(): Unit =
val outer = new Outer
val inner = new outer.Inner
println(inner.bar)
class Outer:
private def foo: String =
"foo"
class Inner:
def bar: String = foo
Notice that it is a lot easier to relate the call-stack with the code now.
Expected Outcome
We expect the student to implement the better-stack in the Scala Debug Adapter using TASTy Query. We already use TASTy Quert in the Scala Debug Adapter to find the scala definition of any runtime method, and this should be reused.
An important requirement is to test the implementation, using the test framework of the Scala Debug Adapter. See for instance the StepFilterTests to get an idea of how we write the tests.
Description
The backend of the compiler encodes all Scala definitions into erased Java definitions. It also introduces intermediate methods that we cannot see directly in the source file.
The debugger allows to view the call stack of a program. For the reason exposed above the call stacks contain encoded names that are hard to interpret.
The goal of the project is to show a better call stack by decoding back all the symbols and hiding some intermediate methods.
Example 1: top level definition and encoded operator
The runtime call-stack is:
Where:
example$package$
is the encoded name of the packageexample
$bang$bang
is the encoded name of the method!!
The better call-stack should be:
Example 2: private method accessed by inner class
The runtime call-stack is:
Where:
example$Outer$$foo
is the encoded name offoo
.Outer$Inner
is the encoded name ofOuter.Inner
.The better call-stack should be:
Example 3: mixin-forwarder
The runtime call-stack is:
Where
Bar.m()
andFoo.m$(Foo)
are some intermediate methods generated by the compiler, called the mixin forwarders.We don't need to show those methods to the user. So a better call-stack should be:
Example 4: given instance and erased signature
The runtime call-stack is:
Where:
foo(Object,Show)
is the erasure of the methodfoo[T](x: T)(using show: Show[T])
Show$given_Show_Int$.show(Object)
is a bridge and should not be shownShow$given_Show_Int$.show(int)
is the show method of the given instanceShow.given_Show_Int
The better call-stack should be:
Notice that it is a lot easier to relate the call-stack with the code now.
Expected Outcome
We expect the student to implement the better-stack in the Scala Debug Adapter using TASTy Query. We already use TASTy Quert in the Scala Debug Adapter to find the scala definition of any runtime method, and this should be reused.
An important requirement is to test the implementation, using the test framework of the Scala Debug Adapter. See for instance the StepFilterTests to get an idea of how we write the tests.
Supervisor
Adrien Piquerez(adrien.piquerez@epfl.ch): Tooling Engineer at the Scala Center