diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala index b39637f86abf..d0077b540107 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala @@ -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) } diff --git a/compiler/src/dotty/tools/dotc/quoted/Toolbox.scala b/compiler/src/dotty/tools/dotc/quoted/Toolbox.scala index 2462d5e5967c..f27605179816 100644 --- a/compiler/src/dotty/tools/dotc/quoted/Toolbox.scala +++ b/compiler/src/dotty/tools/dotc/quoted/Toolbox.scala @@ -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 { @@ -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) } } diff --git a/compiler/src/dotty/tools/dotc/quoted/TreeCleaner.scala b/compiler/src/dotty/tools/dotc/quoted/TreeCleaner.scala new file mode 100644 index 000000000000..cb346ffa555e --- /dev/null +++ b/compiler/src/dotty/tools/dotc/quoted/TreeCleaner.scala @@ -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 + } + } +} diff --git a/tests/run-with-compiler/i3823-c.check b/tests/run-with-compiler/i3823-c.check index 7f63de0f0622..ff7845fd9de5 100644 --- a/tests/run-with-compiler/i3823-c.check +++ b/tests/run-with-compiler/i3823-c.check @@ -1,7 +1,4 @@ { - type T = Int - { - val z: T = 2 - () - } + val z: Int = 2 + () } diff --git a/tests/run-with-compiler/i3876-b.check b/tests/run-with-compiler/i3876-b.check index 0b029c8e91c2..2a3f8f91f175 100644 --- a/tests/run-with-compiler/i3876-b.check +++ b/tests/run-with-compiler/i3876-b.check @@ -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) } diff --git a/tests/run-with-compiler/i3876-c.check b/tests/run-with-compiler/i3876-c.check index 494f0ebab329..60a13f645202 100644 --- a/tests/run-with-compiler/i3876-c.check +++ b/tests/run-with-compiler/i3876-c.check @@ -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) } diff --git a/tests/run-with-compiler/i3876.check b/tests/run-with-compiler/i3876.check index f761ebed3277..643927062fa2 100644 --- a/tests/run-with-compiler/i3876.check +++ b/tests/run-with-compiler/i3876.check @@ -1,7 +1,5 @@ 6 { val x$1: Int = 3 - { - x$1.+(x$1) - } + x$1.+(x$1) } diff --git a/tests/run-with-compiler/quote-run-2.check b/tests/run-with-compiler/quote-run-2.check index d9052f8c4d3d..da6a30e8e4d9 100644 --- a/tests/run-with-compiler/quote-run-2.check +++ b/tests/run-with-compiler/quote-run-2.check @@ -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 - } - } - ) -} +) diff --git a/tests/run-with-compiler/quote-run-constants-extract-1.check b/tests/run-with-compiler/quote-run-constants-extract-1.check new file mode 100644 index 000000000000..c2a18854a8bd --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-1.check @@ -0,0 +1,5 @@ +3 +4 +abc +null +OK diff --git a/tests/run-with-compiler/quote-run-constants-extract-1.scala b/tests/run-with-compiler/quote-run-constants-extract-1.scala new file mode 100644 index 000000000000..2d8b5a151655 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-1.scala @@ -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") } + } +} diff --git a/tests/run-with-compiler/quote-run-constants-extract-2.check b/tests/run-with-compiler/quote-run-constants-extract-2.check new file mode 100644 index 000000000000..1cc77395177a --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-2.check @@ -0,0 +1,5 @@ +{ + val y: Double = 3.0.*(3.0) + y +} +9.0 \ No newline at end of file diff --git a/tests/run-with-compiler/quote-run-constants-extract-2.scala b/tests/run-with-compiler/quote-run-constants-extract-2.scala new file mode 100644 index 000000000000..2108a6b604a2 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-2.scala @@ -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) +} diff --git a/tests/run-with-compiler/quote-run-constants-extract-3.check b/tests/run-with-compiler/quote-run-constants-extract-3.check new file mode 100644 index 000000000000..fadb88febacc --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-3.check @@ -0,0 +1,5 @@ +{ + val y: Double = 3.0.*(3.0) + y +} +9.0 diff --git a/tests/run-with-compiler/quote-run-constants-extract-3.scala b/tests/run-with-compiler/quote-run-constants-extract-3.scala new file mode 100644 index 000000000000..2108a6b604a2 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-3.scala @@ -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) +} diff --git a/tests/run-with-compiler/quote-run-constants-extract-4.check b/tests/run-with-compiler/quote-run-constants-extract-4.check new file mode 100644 index 000000000000..a446942980e1 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-4.check @@ -0,0 +1,5 @@ +{ + val y: Double = 4.0.*(4.0) + y +} +16.0 diff --git a/tests/run-with-compiler/quote-run-constants-extract-4.scala b/tests/run-with-compiler/quote-run-constants-extract-4.scala new file mode 100644 index 000000000000..ca31a75211c8 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-4.scala @@ -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) +} diff --git a/tests/run-with-compiler/quote-run-constants-extract-5.check b/tests/run-with-compiler/quote-run-constants-extract-5.check new file mode 100644 index 000000000000..4f9d9a7de996 --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-5.check @@ -0,0 +1,5 @@ +{ + val y: Double = 5.0.*(5.0) + y +} +25.0 diff --git a/tests/run-with-compiler/quote-run-constants-extract-5.scala b/tests/run-with-compiler/quote-run-constants-extract-5.scala new file mode 100644 index 000000000000..84632588cccb --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-5.scala @@ -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) +} diff --git a/tests/run-with-compiler/quote-run-constants-extract-6.check b/tests/run-with-compiler/quote-run-constants-extract-6.check new file mode 100644 index 000000000000..da9e8c9732aa --- /dev/null +++ b/tests/run-with-compiler/quote-run-constants-extract-6.check @@ -0,0 +1,8 @@ +Test.dynamicPower( + { + println("foo") + 2 + } +, 6.0) +foo +36.0 diff --git a/tests/pending/run-with-compiler/quote-run-constants-extract.scala b/tests/run-with-compiler/quote-run-constants-extract-6.scala similarity index 57% rename from tests/pending/run-with-compiler/quote-run-constants-extract.scala rename to tests/run-with-compiler/quote-run-constants-extract-6.scala index 4d4825b94f4d..3e8c8ab84fa2 100644 --- a/tests/pending/run-with-compiler/quote-run-constants-extract.scala +++ b/tests/run-with-compiler/quote-run-constants-extract-6.scala @@ -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) diff --git a/tests/run-with-compiler/quote-run-constants-extract.check b/tests/run-with-compiler/quote-run-constants-extract.check deleted file mode 100644 index 413ade6292a3..000000000000 --- a/tests/run-with-compiler/quote-run-constants-extract.check +++ /dev/null @@ -1,36 +0,0 @@ -3 -4 -abc -null -OK -{ - { - val y: Double = 3.0.*(3.0) - y - } -} -9.0 -{ - { - val y: Double = 4.0.*(4.0) - y - } -} -16.0 -{ - { - val y: Double = 5.0.*(5.0) - y - } -} -25.0 -{ - Test.dynamicPower( - { - println("foo") - 2 - } - , 6.0) -} -foo -36.0 diff --git a/tests/run-with-compiler/quote-run-staged-interpreter.check b/tests/run-with-compiler/quote-run-staged-interpreter.check index b38370ccd67b..1ecdf98f6e71 100644 --- a/tests/run-with-compiler/quote-run-staged-interpreter.check +++ b/tests/run-with-compiler/quote-run-staged-interpreter.check @@ -1,10 +1,5 @@ { - { - (x: Int) => - { - 2.+(x).+(4) - } - } + (x: Int) => 2.+(x).+(4) } 6 8 diff --git a/tests/run-with-compiler/quote-show-blocks-raw.check b/tests/run-with-compiler/quote-show-blocks-raw.check new file mode 100644 index 000000000000..d5000f92059b --- /dev/null +++ b/tests/run-with-compiler/quote-show-blocks-raw.check @@ -0,0 +1,32 @@ +{ + println(1) + { + println(2) + { + println(3) + { + println(4) + { + println(5) + () + } + } + } + } +} +{ + { + { + { + { + () + println(5) + } + println(4) + } + println(3) + } + println(2) + } + println(1) +} diff --git a/tests/run-with-compiler/quote-show-blocks-raw.scala b/tests/run-with-compiler/quote-show-blocks-raw.scala new file mode 100644 index 000000000000..cb42ee211e18 --- /dev/null +++ b/tests/run-with-compiler/quote-show-blocks-raw.scala @@ -0,0 +1,25 @@ + +import dotty.tools.dotc.quoted.Toolbox._ + +import scala.quoted._ +import scala.quoted.Liftable._ + +object Test { + def main(args: Array[String]): Unit = { + implicit val settings = Settings.show(rawTree = true) + + def a(n: Int, x: Expr[Unit]): Expr[Unit] = + if (n == 0) x + else a(n - 1, '{ println(~n.toExpr); ~x }) + + println(a(5, ()).show) + + + def b(n: Int, x: Expr[Unit]): Expr[Unit] = + if (n == 0) x + else b(n - 1, '{ ~x; println(~n.toExpr) }) + + println(b(5, ()).show) + } + +} diff --git a/tests/run-with-compiler/quote-show-blocks.check b/tests/run-with-compiler/quote-show-blocks.check new file mode 100644 index 000000000000..e3dc2c1ff20d --- /dev/null +++ b/tests/run-with-compiler/quote-show-blocks.check @@ -0,0 +1,15 @@ +{ + println(1) + println(2) + println(3) + println(4) + println(5) + () +} +{ + println(5) + println(4) + println(3) + println(2) + println(1) +} diff --git a/tests/run-with-compiler/quote-show-blocks.scala b/tests/run-with-compiler/quote-show-blocks.scala new file mode 100644 index 000000000000..0cbac3d943fe --- /dev/null +++ b/tests/run-with-compiler/quote-show-blocks.scala @@ -0,0 +1,24 @@ + +import dotty.tools.dotc.quoted.Toolbox._ + +import scala.quoted._ +import scala.quoted.Liftable._ + +object Test { + def main(args: Array[String]): Unit = { + + def a(n: Int, x: Expr[Unit]): Expr[Unit] = + if (n == 0) x + else a(n - 1, '{ println(~n.toExpr); ~x }) + + println(a(5, ()).show) + + + def b(n: Int, x: Expr[Unit]): Expr[Unit] = + if (n == 0) x + else b(n - 1, '{ ~x; println(~n.toExpr) }) + + println(b(5, ()).show) + } + +}