Skip to content

Add quote.show tree cleaner #4052

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class QuoteDriver extends Driver {
def show(tree: Tree, ctx: Context): String = {
val printer = new DecompilerPrinter(ctx)
val pageWidth = ctx.settings.pageWidth.value(ctx)
printer.toText(tree).mkString(pageWidth, false)
val tree1 = if (settings.rawTree) tree else (new TreeCleaner).transform(tree)(ctx)
printer.toText(tree1).mkString(pageWidth, false)
}
withTree(expr, show, settings)
}
Expand Down
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/quoted/Toolbox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ object Toolbox {

}

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

object Settings {

Expand All @@ -69,19 +69,22 @@ object Toolbox {
): Settings[Run] = {
var compilerArgs1 = compilerArgs
if (optimise) compilerArgs1 = "-optimise" :: compilerArgs1
new Settings(outDir, compilerArgs1)
new Settings(outDir, false, compilerArgs1)
}

/** Quote show settings
* @param color Print output with colors
* @param rawTree Do not remove quote tree artifacts
* @param compilerArgs Compiler arguments. Use only if you know what you are doing.
*/
def show(
color: Boolean = false,
rawTree: Boolean = false,
compilerArgs: List[String] = Nil
): Settings[Show] = {
var compilerArgs1 = compilerArgs
compilerArgs1 = s"-color:${if (color) "always" else "never"}" :: compilerArgs1
new Settings(None, compilerArgs1)
new Settings(None, rawTree, compilerArgs1)
}

}
Expand Down
46 changes: 46 additions & 0 deletions compiler/src/dotty/tools/dotc/quoted/TreeCleaner.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dotty.tools.dotc.quoted

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Constants._
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Types._

/** Clean up quote artifacts from the tree to make it simpler to read.
* - Flattens block and remove blocks with not statements
* - Inline type aliases in the tree
*/
class TreeCleaner extends tpd.TreeMap {
import tpd._

/** List of symbols and their types for type aliases `type T = U` */
private[this] var aliasesSyms: List[Symbol] = Nil
private[this] var aliasesTypes: List[Type] = Nil

override def transform(tree: Tree)(implicit ctx: Context): Tree = {
val tree0 = tree match {
case TypeDef(_, TypeBoundsTree(lo, hi)) if lo == hi =>
aliasesSyms = tree.symbol :: aliasesSyms
aliasesTypes = lo.tpe :: aliasesTypes
Literal(Constant(()))
case _ => tree
}

super.transform(tree0) match {
case Block(Nil, expr1) => expr1
case Block(stats1, expr1) =>
val flatStats = stats1.flatMap {
case Block(stats2, expr2) => stats2 ::: expr2 :: Nil
case Literal(Constant(())) => Nil
case stat => stat :: Nil
}
expr1 match {
case Block(stats3, expr3) => Block(flatStats ::: stats3, expr3)
case expr3 => Block(flatStats, expr3)
}
case tree1: TypeTree => TypeTree(tree1.tpe.subst(aliasesSyms, aliasesTypes))
case tree1 => tree1
}
}
}
7 changes: 2 additions & 5 deletions tests/run-with-compiler/i3823-c.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
type T = Int
{
val z: T = 2
()
}
val z: Int = 2
()
}
6 changes: 2 additions & 4 deletions tests/run-with-compiler/i3876-b.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
6
{
val x$1: Int = 3
{
def f(x: Int): Int = x.+(x)
f(x$1)
}
def f(x: Int): Int = x.+(x)
f(x$1)
}
18 changes: 8 additions & 10 deletions tests/run-with-compiler/i3876-c.check
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
6
{
val x$1: Int = 3
{
val f:
Function1[Int, Int]
{
def apply(x: Int): Int
}
=
val f:
Function1[Int, Int]
{
(x: Int) => x.+(x)
def apply(x: Int): Int
}
(f: (x: Int) => Int).apply(x$1)
}
=
{
(x: Int) => x.+(x)
}
(f: (x: Int) => Int).apply(x$1)
}
4 changes: 1 addition & 3 deletions tests/run-with-compiler/i3876.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
6
{
val x$1: Int = 3
{
x$1.+(x$1)
}
x$1.+(x$1)
}
16 changes: 5 additions & 11 deletions tests/run-with-compiler/quote-run-2.check
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
1.0
5.0
{
val y: Double = 5.0.*(5.0)
y
}
5.0.*(
{
val y: Double = 5.0.*(5.0)
y
}
}
{
5.0.*(
{
{
val y: Double = 5.0.*(5.0)
y
}
}
)
}
)
5 changes: 5 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-1.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3
4
abc
null
OK
15 changes: 15 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import scala.quoted._

import dotty.tools.dotc.quoted.Toolbox._

object Test {

def main(args: Array[String]): Unit = {
(3: Expr[Int]) match { case Constant(n) => println(n) }
'(4) match { case Constant(n) => println(n) }
'("abc") match { case Constant(n) => println(n) }
'(null) match { case Constant(n) => println(n) }

'(new Object) match { case Constant(n) => println(n); case _ => println("OK") }
}
}
5 changes: 5 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
val y: Double = 3.0.*(3.0)
y
}
9.0
30 changes: 30 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import scala.quoted._

import dotty.tools.dotc.quoted.Toolbox._

object Test {

def main(args: Array[String]): Unit = {
// 2 is a lifted constant
println(power(2, 3.0).show)
println(power(2, 3.0).run)
}

def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
n match {
case Constant(n1) => powerCode(n1, x)
case _ => '{ dynamicPower(~n, ~x) }
}
}

private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
if (n == 0) '(1.0)
else if (n == 1) x
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
else '{ ~x * ~powerCode(n - 1, x) }

def dynamicPower(n: Int, x: Double): Double =
if (n == 0) 1.0
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
else x * dynamicPower(n - 1, x)
}
5 changes: 5 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-3.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
val y: Double = 3.0.*(3.0)
y
}
9.0
30 changes: 30 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import scala.quoted._

import dotty.tools.dotc.quoted.Toolbox._

object Test {

def main(args: Array[String]): Unit = {
// 2 is a lifted constant
println(power(2, 3.0).show)
println(power(2, 3.0).run)
}

def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
n match {
case Constant(n1) => powerCode(n1, x)
case _ => '{ dynamicPower(~n, ~x) }
}
}

private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
if (n == 0) '(1.0)
else if (n == 1) x
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
else '{ ~x * ~powerCode(n - 1, x) }

def dynamicPower(n: Int, x: Double): Double =
if (n == 0) 1.0
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
else x * dynamicPower(n - 1, x)
}
5 changes: 5 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-4.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
val y: Double = 4.0.*(4.0)
y
}
16.0
31 changes: 31 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-4.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import scala.quoted._

import dotty.tools.dotc.quoted.Toolbox._

object Test {

def main(args: Array[String]): Unit = {
// n is a lifted constant
val n = 2
println(power(n, 4.0).show)
println(power(n, 4.0).run)
}

def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
n match {
case Constant(n1) => powerCode(n1, x)
case _ => '{ dynamicPower(~n, ~x) }
}
}

private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
if (n == 0) '(1.0)
else if (n == 1) x
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
else '{ ~x * ~powerCode(n - 1, x) }

def dynamicPower(n: Int, x: Double): Double =
if (n == 0) 1.0
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
else x * dynamicPower(n - 1, x)
}
5 changes: 5 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-5.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
val y: Double = 5.0.*(5.0)
y
}
25.0
30 changes: 30 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-5.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import scala.quoted._

import dotty.tools.dotc.quoted.Toolbox._

object Test {

def main(args: Array[String]): Unit = {
// n is a constant in a quote
println(power('(2), 5.0).show)
println(power('(2), 5.0).run)
}

def power(n: Expr[Int], x: Expr[Double]): Expr[Double] = {
n match {
case Constant(n1) => powerCode(n1, x)
case _ => '{ dynamicPower(~n, ~x) }
}
}

private def powerCode(n: Int, x: Expr[Double]): Expr[Double] =
if (n == 0) '(1.0)
else if (n == 1) x
else if (n % 2 == 0) '{ { val y = ~x * ~x; ~powerCode(n / 2, '(y)) } }
else '{ ~x * ~powerCode(n - 1, x) }

def dynamicPower(n: Int, x: Double): Double =
if (n == 0) 1.0
else if (n % 2 == 0) dynamicPower(n / 2, x * x)
else x * dynamicPower(n - 1, x)
}
8 changes: 8 additions & 0 deletions tests/run-with-compiler/quote-run-constants-extract-6.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Test.dynamicPower(
{
println("foo")
2
}
, 6.0)
foo
36.0
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,6 @@ import dotty.tools.dotc.quoted.Toolbox._
object Test {

def main(args: Array[String]): Unit = {
(3: Expr[Int]) match { case Constant(n) => println(n) }
'(4) match { case Constant(n) => println(n) }
'("abc") match { case Constant(n) => println(n) }
'(null) match { case Constant(n) => println(n) }

'(new Object) match { case Constant(n) => println(n); case _ => println("OK") }


// 2 is a lifted constant
println(power(2, 3.0).show)
println(power(2, 3.0).run)

// n is a lifted constant
val n = 2
println(power(n, 4.0).show)
println(power(n, 4.0).run)

// n is a constant in a quote
println(power('(2), 5.0).show)
println(power('(2), 5.0).run)

// n2 is clearly not a constant
val n2 = '{ println("foo"); 2 }
println(power(n2, 6.0).show)
Expand Down
Loading