Skip to content

Commit 412fe37

Browse files
Merge pull request #4052 from dotty-staging/add-quote-show-tree-cleaner
Add quote.show tree cleaner
2 parents c7ac32a + 8216c5a commit 412fe37

26 files changed

+338
-100
lines changed

compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ class QuoteDriver extends Driver {
4444
def show(tree: Tree, ctx: Context): String = {
4545
val printer = new DecompilerPrinter(ctx)
4646
val pageWidth = ctx.settings.pageWidth.value(ctx)
47-
printer.toText(tree).mkString(pageWidth, false)
47+
val tree1 = if (settings.rawTree) tree else (new TreeCleaner).transform(tree)(ctx)
48+
printer.toText(tree1).mkString(pageWidth, false)
4849
}
4950
withTree(expr, show, settings)
5051
}

compiler/src/dotty/tools/dotc/quoted/Toolbox.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object Toolbox {
5353

5454
}
5555

56-
class Settings[T] private (val outDir: Option[String], val compilerArgs: List[String])
56+
class Settings[T] private (val outDir: Option[String], val rawTree: Boolean, val compilerArgs: List[String])
5757

5858
object Settings {
5959

@@ -69,19 +69,22 @@ object Toolbox {
6969
): Settings[Run] = {
7070
var compilerArgs1 = compilerArgs
7171
if (optimise) compilerArgs1 = "-optimise" :: compilerArgs1
72-
new Settings(outDir, compilerArgs1)
72+
new Settings(outDir, false, compilerArgs1)
7373
}
7474

7575
/** Quote show settings
76+
* @param color Print output with colors
77+
* @param rawTree Do not remove quote tree artifacts
7678
* @param compilerArgs Compiler arguments. Use only if you know what you are doing.
7779
*/
7880
def show(
7981
color: Boolean = false,
82+
rawTree: Boolean = false,
8083
compilerArgs: List[String] = Nil
8184
): Settings[Show] = {
8285
var compilerArgs1 = compilerArgs
8386
compilerArgs1 = s"-color:${if (color) "always" else "never"}" :: compilerArgs1
84-
new Settings(None, compilerArgs1)
87+
new Settings(None, rawTree, compilerArgs1)
8588
}
8689

8790
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.ast.Trees._
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Contexts._
6+
import dotty.tools.dotc.core.Constants._
7+
import dotty.tools.dotc.core.Symbols._
8+
import dotty.tools.dotc.core.Types._
9+
10+
/** Clean up quote artifacts from the tree to make it simpler to read.
11+
* - Flattens block and remove blocks with not statements
12+
* - Inline type aliases in the tree
13+
*/
14+
class TreeCleaner extends tpd.TreeMap {
15+
import tpd._
16+
17+
/** List of symbols and their types for type aliases `type T = U` */
18+
private[this] var aliasesSyms: List[Symbol] = Nil
19+
private[this] var aliasesTypes: List[Type] = Nil
20+
21+
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
22+
val tree0 = tree match {
23+
case TypeDef(_, TypeBoundsTree(lo, hi)) if lo == hi =>
24+
aliasesSyms = tree.symbol :: aliasesSyms
25+
aliasesTypes = lo.tpe :: aliasesTypes
26+
Literal(Constant(()))
27+
case _ => tree
28+
}
29+
30+
super.transform(tree0) match {
31+
case Block(Nil, expr1) => expr1
32+
case Block(stats1, expr1) =>
33+
val flatStats = stats1.flatMap {
34+
case Block(stats2, expr2) => stats2 ::: expr2 :: Nil
35+
case Literal(Constant(())) => Nil
36+
case stat => stat :: Nil
37+
}
38+
expr1 match {
39+
case Block(stats3, expr3) => Block(flatStats ::: stats3, expr3)
40+
case expr3 => Block(flatStats, expr3)
41+
}
42+
case tree1: TypeTree => TypeTree(tree1.tpe.subst(aliasesSyms, aliasesTypes))
43+
case tree1 => tree1
44+
}
45+
}
46+
}

tests/run-with-compiler/i3823-c.check

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
2-
type T = Int
3-
{
4-
val z: T = 2
5-
()
6-
}
2+
val z: Int = 2
3+
()
74
}

tests/run-with-compiler/i3876-b.check

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
6
22
{
33
val x$1: Int = 3
4-
{
5-
def f(x: Int): Int = x.+(x)
6-
f(x$1)
7-
}
4+
def f(x: Int): Int = x.+(x)
5+
f(x$1)
86
}

tests/run-with-compiler/i3876-c.check

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
6
22
{
33
val x$1: Int = 3
4-
{
5-
val f:
6-
Function1[Int, Int]
7-
{
8-
def apply(x: Int): Int
9-
}
10-
=
4+
val f:
5+
Function1[Int, Int]
116
{
12-
(x: Int) => x.+(x)
7+
def apply(x: Int): Int
138
}
14-
(f: (x: Int) => Int).apply(x$1)
15-
}
9+
=
10+
{
11+
(x: Int) => x.+(x)
12+
}
13+
(f: (x: Int) => Int).apply(x$1)
1614
}

tests/run-with-compiler/i3876.check

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
6
22
{
33
val x$1: Int = 3
4-
{
5-
x$1.+(x$1)
6-
}
4+
x$1.+(x$1)
75
}
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
1.0
22
5.0
33
{
4+
val y: Double = 5.0.*(5.0)
5+
y
6+
}
7+
5.0.*(
48
{
59
val y: Double = 5.0.*(5.0)
610
y
711
}
8-
}
9-
{
10-
5.0.*(
11-
{
12-
{
13-
val y: Double = 5.0.*(5.0)
14-
y
15-
}
16-
}
17-
)
18-
}
12+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
3
2+
4
3+
abc
4+
null
5+
OK
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
(3: Expr[Int]) match { case Constant(n) => println(n) }
9+
'(4) match { case Constant(n) => println(n) }
10+
'("abc") match { case Constant(n) => println(n) }
11+
'(null) match { case Constant(n) => println(n) }
12+
13+
'(new Object) match { case Constant(n) => println(n); case _ => println("OK") }
14+
}
15+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
val y: Double = 3.0.*(3.0)
3+
y
4+
}
5+
9.0
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
// 2 is a lifted constant
9+
println(power(2, 3.0).show)
10+
println(power(2, 3.0).run)
11+
}
12+
13+
def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
14+
n match {
15+
case Constant(n1) => powerCode(n1, x)
16+
case _ => '{ dynamicPower(~n, ~x) }
17+
}
18+
}
19+
20+
private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
21+
if (n == 0) '(1.0)
22+
else if (n == 1) x
23+
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
24+
else '{ ~x * ~powerCode(n - 1, x) }
25+
26+
def dynamicPower(n: Int, x: Double): Double =
27+
if (n == 0) 1.0
28+
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
29+
else x * dynamicPower(n - 1, x)
30+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
val y: Double = 3.0.*(3.0)
3+
y
4+
}
5+
9.0
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
// 2 is a lifted constant
9+
println(power(2, 3.0).show)
10+
println(power(2, 3.0).run)
11+
}
12+
13+
def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
14+
n match {
15+
case Constant(n1) => powerCode(n1, x)
16+
case _ => '{ dynamicPower(~n, ~x) }
17+
}
18+
}
19+
20+
private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
21+
if (n == 0) '(1.0)
22+
else if (n == 1) x
23+
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
24+
else '{ ~x * ~powerCode(n - 1, x) }
25+
26+
def dynamicPower(n: Int, x: Double): Double =
27+
if (n == 0) 1.0
28+
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
29+
else x * dynamicPower(n - 1, x)
30+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
val y: Double = 4.0.*(4.0)
3+
y
4+
}
5+
16.0
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
// n is a lifted constant
9+
val n = 2
10+
println(power(n, 4.0).show)
11+
println(power(n, 4.0).run)
12+
}
13+
14+
def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
15+
n match {
16+
case Constant(n1) => powerCode(n1, x)
17+
case _ => '{ dynamicPower(~n, ~x) }
18+
}
19+
}
20+
21+
private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
22+
if (n == 0) '(1.0)
23+
else if (n == 1) x
24+
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
25+
else '{ ~x * ~powerCode(n - 1, x) }
26+
27+
def dynamicPower(n: Int, x: Double): Double =
28+
if (n == 0) 1.0
29+
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
30+
else x * dynamicPower(n - 1, x)
31+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
val y: Double = 5.0.*(5.0)
3+
y
4+
}
5+
25.0
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
// n is a constant in a quote
9+
println(power('(2), 5.0).show)
10+
println(power('(2), 5.0).run)
11+
}
12+
13+
def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
14+
n match {
15+
case Constant(n1) => powerCode(n1, x)
16+
case _ => '{ dynamicPower(~n, ~x) }
17+
}
18+
}
19+
20+
private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
21+
if (n == 0) '(1.0)
22+
else if (n == 1) x
23+
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
24+
else '{ ~x * ~powerCode(n - 1, x) }
25+
26+
def dynamicPower(n: Int, x: Double): Double =
27+
if (n == 0) 1.0
28+
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
29+
else x * dynamicPower(n - 1, x)
30+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Test.dynamicPower(
2+
{
3+
println("foo")
4+
2
5+
}
6+
, 6.0)
7+
foo
8+
36.0

tests/pending/run-with-compiler/quote-run-constants-extract.scala renamed to tests/run-with-compiler/quote-run-constants-extract-6.scala

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,6 @@ import dotty.tools.dotc.quoted.Toolbox._
55
object Test {
66

77
def main(args: Array[String]): Unit = {
8-
(3: Expr[Int]) match { case Constant(n) => println(n) }
9-
'(4) match { case Constant(n) => println(n) }
10-
'("abc") match { case Constant(n) => println(n) }
11-
'(null) match { case Constant(n) => println(n) }
12-
13-
'(new Object) match { case Constant(n) => println(n); case _ => println("OK") }
14-
15-
16-
// 2 is a lifted constant
17-
println(power(2, 3.0).show)
18-
println(power(2, 3.0).run)
19-
20-
// n is a lifted constant
21-
val n = 2
22-
println(power(n, 4.0).show)
23-
println(power(n, 4.0).run)
24-
25-
// n is a constant in a quote
26-
println(power('(2), 5.0).show)
27-
println(power('(2), 5.0).run)
28-
298
// n2 is clearly not a constant
309
val n2 = '{ println("foo"); 2 }
3110
println(power(n2, 6.0).show)

0 commit comments

Comments
 (0)