-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improve decompilation to generate compilable sources #4526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Here is a simple one that fails class Foo
object Foo generating
It just misses a |
generates /** Decompiled from output/Foo.class */
class Foo(x: Int) {
private[this] val x: Int
} There is an additional statement created internally to represent the field of the constructor argument. We just need to look at it's flags and filter it out if it is one of those. |
package bar
class Foo {
protected[bar] def foo(): Int = 0
} with /** Decompiled from output/bar/Foo.class */
package bar {
class Foo() {
protected def foo(): Int = 0
}
} It is missing the |
Trying Varargs: package bar
class Foo {
def printAll(strings: String*) = strings.map(println)
} produces /** Decompiled from output/bar/Foo.class */
package bar {
class Foo() {
def printAll(strings: Seq[String] @scala.annotation.internal.Repeated()):
Seq[Unit]
=
strings.map[Unit, Seq[Unit]]((x: Any) => println(x))(
collection.Seq.canBuildFrom[Unit]
)
}
} Compilation of this works, but annotation shouldn't occur. |
class Foo {
def justdoit (f : Either[Int,String]) : String = {
f match {
case Left(i) => i.toString
case Right(s) => s
}
}
} produces /** Decompiled from output/Foo.class */
class Foo() {
def justdoit(f: Either[Int, String]): String =
{
f match
{
case Left.unapply[Int, String](i @ _): Left[Int, String] =>
i.toString()
case Right.unapply[Int, String](s @ _): Right[Int, String] =>
s: String
}
}
}
|
Calling varargs method: package bar
class Foo {
def printAll(strings: String*) = strings.foreach(println)
def printDefault() = printAll("One", "Two", "Three")
} produces /** Decompiled from output/bar/Foo.class */
package bar {
class Foo() {
def printAll(strings: Seq[String] @scala.annotation.internal.Repeated()):
Unit
= strings.foreach[Unit]((x: Any) => println(x))
def printDefault(): Unit =
this.printAll(["One","Two","Three" : String]: String*)
}
} but should be def printDefault(): Unit =
this.printAll(Seq("One","Two","Three"): _*) |
…la#4526) This fixes printing of classes with companion objects so that they don't appear on the same line. Example case: class Foo object Foo will be decompiled into class Foo() {} object Foo {} where before they would be printed on the same line, failing compilation.
Fix printing of classes with companion objects in the decompiler (#4526)
…-4526 Add some regression tests for #4526
Remove annotation from function declaration Explicitly type non sequence literal arguments as varargs in function call (_*)
Remove annotation from function declaration Explicitly type non sequence literal arguments as varargs in function call (_*)
Uh oh!
There was an error while loading. Please reload this page.
Currently the decompilation printer
scala.tasty.util.ShowSourceCode
is the main step in decompilation of class files. It is a glorified TASTY tree pretty printer. It is still quite rough but it prints out a version of the sources that are fully typed (all types are inferred, all implicit are resolved, ...). There are still two kinds of issues to iron out: (i) Resugaring and (ii) leaking internals.The Goal is to have a decompiler that produces back sources that can be recompiled and would generate the same program. We expect to fix this by small incremental steps, supporting more and more features.
Currently, the simplest way to test if some code is decompiled correctly is to create a file
Foo.scala
(or any of the available tests intests/pos
), write some code in it and run the following scripts from the dotty project:If some issue is fixed, regression test must be added by adding a
.scala
source intests/pos
along with a.decompiled
with the same name. For exampletests/pos/lambda.scala
andtests/pos/lambda.decompiled
.You can test this file by running
sbt testFromTasty
(orsbt "testFromTasty XYZ"
whereXYZ
is the name of the test), if the test fails a.decompiled.out
will be generated besides the.decompiled
. You can just rename it if the output of the current run was actually correct.Note that this file is currently sensitive to spaces at the end of the line (painful and needs to be fixed) and that
FromTastyTests
append to any existing.decompiled.out
which is problematic if you still have one from a previousFromTastyTests
. There is also no way to only run a single test underFromTastyTests
which is another improvement that must be done.The text was updated successfully, but these errors were encountered: