From 0dc058727aed8f433295364a18ceb7e85b6c9c48 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 23 Nov 2018 20:52:49 +0100 Subject: [PATCH] Handle empty blocks in the printer Avoid printing extra blocks and inline nodes --- .../tools/dotc/printing/RefinedPrinter.scala | 4 +- .../test/dotc/pos-recompilation.whitelist | 4 - .../src/scala/tasty/reflect/Printers.scala | 115 +++++++++++++----- tests/pos/i2104b.decompiled | 10 +- tests/pos/i4526b.decompiled | 12 +- tests/pos/lambda.decompiled | 6 +- tests/pos/simpleDoWhile.decompiled | 4 +- tests/pos/simpleInline.decompiled | 4 +- tests/pos/simpleMatchCase.decompiled | 10 +- tests/pos/simpleWhile.decompiled | 4 +- tests/pos/t3869.decompiled | 4 +- tests/pos/t704.decompiled | 7 +- .../quote-impure-by-name.check | 4 +- tests/run-with-compiler/quote-nested-3.check | 1 - .../quote-show-blocks-raw.check | 36 ------ .../quote-show-blocks-raw.scala | 25 ---- tests/run-with-compiler/shonan-hmm.check | 4 - tests/run/literals.decompiled | 10 +- 18 files changed, 110 insertions(+), 154 deletions(-) delete mode 100644 tests/run-with-compiler/quote-show-blocks-raw.check delete mode 100644 tests/run-with-compiler/quote-show-blocks-raw.scala diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 038d65920e32..2d477e059520 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -405,8 +405,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SeqLiteral(elems, elemtpt) => "[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]" case tree @ Inlined(call, bindings, body) => - (("/* inlined from " ~ toText(call) ~ " */ ") `provided` - !call.isEmpty && !homogenizedView && !ctx.settings.YshowNoInline.value) ~ + (("/* inlined from " ~ (if (call.isEmpty) "outside" else toText(call)) ~ " */ ") `provided` + !homogenizedView && !ctx.settings.YshowNoInline.value) ~ blockText(bindings :+ body) case tpt: untpd.DerivedTypeTree => "" diff --git a/compiler/test/dotc/pos-recompilation.whitelist b/compiler/test/dotc/pos-recompilation.whitelist index b9b0793ea58d..6a2d586579f5 100644 --- a/compiler/test/dotc/pos-recompilation.whitelist +++ b/compiler/test/dotc/pos-recompilation.whitelist @@ -38,7 +38,6 @@ CoderTrait collectGenericCC collections_1 comp-rec-test -companions compile1 conforms conformsWild @@ -317,7 +316,6 @@ i831 i864 i877 i878 -i880 i903 i938 i939 @@ -438,7 +436,6 @@ propagate quote-1 quote-lift-inline-params-b quote-non-static-macro -quote-this range rangepos rangepos-anonapply @@ -883,7 +880,6 @@ t613 t6145 t6146 t615 -t6157 t616 t6184 t6201 diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 4b725dbad510..de4a5b9b7fd6 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -646,6 +646,17 @@ trait Printers printTree(body) } + case IsDefDef(ddef @ DefDef(name, targs, argss, _, rhsOpt)) if name.startsWith("$anonfun") => + // Decompile lambda definition + assert(targs.isEmpty) + val args :: Nil = argss + val Some(rhs) = rhsOpt + inParens { + printArgsDefs(args) + this += " => " + printTree(rhs) + } + case IsDefDef(ddef @ DefDef(name, targs, argss, tpt, rhs)) => printDefAnnotations(ddef) @@ -777,34 +788,13 @@ trait Printers case IsValDef(tree) => !tree.symbol.flags.isObject case _ => true } + printFlatBlock(stats, expr) - expr match { - case Term.Lambda(_, _) => - // Decompile lambda from { def annon$(...) = ...; closure(annon$, ...)} - assert(stats.size == 1) - val DefDef(_, _, args :: Nil, _, Some(rhs)) :: Nil = stats - inParens { - printArgsDefs(args) - this += " => " - printTree(rhs) - } - case _ => - this += "{" - indented { - printStats(stats, expr) - } - this += lineBreak() += "}" - } - - case Term.Inlined(call, bindings, expansion) => // FIXME: Don't print Inlined with empty calls? - this += "{ // inlined" - indented { - printStats(bindings, expansion) - } - this += lineBreak() += "}" + case Term.Inlined(_, bindings, expansion) => + printFlatBlock(bindings, expansion) case Term.Lambda(meth, tpt) => - // Printed in Term.Block branch + // Printed in by it's DefDef this case Term.If(cond, thenp, elsep) => @@ -847,15 +837,80 @@ trait Printers } + def flatBlock(stats: List[Statement], expr: Term): (List[Statement], Term) = { + val flatStats = List.newBuilder[Statement] + def extractFlatStats(stat: Statement): Unit = stat match { + case Term.Block(stats1, expr1) => + val it = stats1.iterator + while (it.hasNext) + extractFlatStats(it.next()) + extractFlatStats(expr1) + case Term.Inlined(_, bindings, expansion) => + val it = bindings.iterator + while (it.hasNext) + extractFlatStats(it.next()) + extractFlatStats(expansion) + case Term.Literal(Constant.Unit()) => // ignore + case stat => flatStats += stat + } + def extractFlatExpr(term: Term): Term = term match { + case Term.Block(stats1, expr1) => + val it = stats1.iterator + while (it.hasNext) + extractFlatStats(it.next()) + extractFlatExpr(expr1) + case Term.Inlined(_, bindings, expansion) => + val it = bindings.iterator + while (it.hasNext) + extractFlatStats(it.next()) + extractFlatExpr(expansion) + case term => term + } + val it = stats.iterator + while (it.hasNext) + extractFlatStats(it.next()) + val flatExpr = extractFlatExpr(expr) + (flatStats.result(), flatExpr) + } + + def printFlatBlock(stats: List[Statement], expr: Term): Buffer = { + val (stats1, expr1) = flatBlock(stats, expr) + // Remove Term.Lambda nodes, lambdas are printed by their definition + val stats2 = stats1.filter { case Term.Lambda(_, _) => false; case _ => true } + val (stats3, expr3) = expr1 match { + case Term.Lambda(_, _) => + val init :+ last = stats2 + (init, last) + case _ => (stats2, expr1) + } + if (stats3.isEmpty) { + printTree(expr3) + } else { + this += "{" + indented { + printStats(stats3, expr3) + } + this += lineBreak() += "}" + } + } + def printStats(stats: List[Tree], expr: Tree): Unit = { def printSeparator(next: Tree): Unit = { // Avoid accidental application of opening `{` on next line with a double break + def rec(next: Tree): Unit = next match { + case Term.Block(stats, _) if stats.nonEmpty => this += doubleLineBreak() + case Term.Inlined(_, bindings, _) if bindings.nonEmpty => this += doubleLineBreak() + case Term.Select(qual, _) => rec(qual) + case Term.Apply(fn, _) => rec(fn) + case Term.TypeApply(fn, _) => rec(fn) + case _ => this += lineBreak() + } next match { - case Term.Block(_, _) => this += doubleLineBreak() - case Term.Inlined(_, _, _) => this += doubleLineBreak() - case Term.Select(qual, _) => printSeparator(qual) - case Term.Apply(fn, _) => printSeparator(fn) - case Term.TypeApply(fn, _) => printSeparator(fn) + case IsTerm(term) => + flatBlock(Nil, term) match { + case (next :: _, _) => rec(next) + case (Nil, next) => rec(next) + } case _ => this += lineBreak() } } diff --git a/tests/pos/i2104b.decompiled b/tests/pos/i2104b.decompiled index 9be9677bea4a..9d240a3391a3 100644 --- a/tests/pos/i2104b.decompiled +++ b/tests/pos/i2104b.decompiled @@ -34,10 +34,8 @@ case class Pair[A, B](_1: A, _2: B) { object Pair extends scala.AnyRef() /** Decompiled from out/posTestFromTasty/pos/i2104b/Test.class */ object Test { - def main(args: scala.Array[scala.Predef.String]): scala.Unit = { - Cons.apply[scala.Option[scala.Int], scala.None.type](scala.Option.apply[scala.Int](1), scala.None) match { - case Cons(scala.Some(i), scala.None) => - () - } + def main(args: scala.Array[scala.Predef.String]): scala.Unit = Cons.apply[scala.Option[scala.Int], scala.None.type](scala.Option.apply[scala.Int](1), scala.None) match { + case Cons(scala.Some(i), scala.None) => + () } -} \ No newline at end of file +} diff --git a/tests/pos/i4526b.decompiled b/tests/pos/i4526b.decompiled index d16c935f11f4..a4958478ff11 100644 --- a/tests/pos/i4526b.decompiled +++ b/tests/pos/i4526b.decompiled @@ -1,11 +1,9 @@ /** Decompiled from out/posTestFromTasty/pos/i4526b/Foo.class */ class Foo() { - def justdoit(f: scala.Either[scala.Int, scala.Predef.String]): scala.Predef.String = { - f match { - case scala.Left(i) => - i.toString() - case scala.Right(s) => - (s: java.lang.String) - } + def justdoit(f: scala.Either[scala.Int, scala.Predef.String]): scala.Predef.String = f match { + case scala.Left(i) => + i.toString() + case scala.Right(s) => + (s: java.lang.String) } } diff --git a/tests/pos/lambda.decompiled b/tests/pos/lambda.decompiled index ddcdfd5fe5f4..fc1fcf67c6d6 100644 --- a/tests/pos/lambda.decompiled +++ b/tests/pos/lambda.decompiled @@ -1,11 +1,7 @@ /** Decompiled from out/posTestFromTasty/pos/lambda/foo/Foo.class */ package foo { class Foo() { - { - ((x: scala.Int) => { - 2 - }) - } + ((x: scala.Int) => 2) val a: scala.Function1[scala.Int, scala.Int] = ((x: scala.Int) => x.*(x)) } } diff --git a/tests/pos/simpleDoWhile.decompiled b/tests/pos/simpleDoWhile.decompiled index 10a498fc026f..90fbe2fb3d41 100644 --- a/tests/pos/simpleDoWhile.decompiled +++ b/tests/pos/simpleDoWhile.decompiled @@ -2,8 +2,6 @@ class Foo() { def foo: scala.Unit = { var i: scala.Int = 1 - do { - i = 0 - } while (i.!=(0)) + do i = 0 while (i.!=(0)) } } diff --git a/tests/pos/simpleInline.decompiled b/tests/pos/simpleInline.decompiled index a75db7d705d3..f0b400adb998 100644 --- a/tests/pos/simpleInline.decompiled +++ b/tests/pos/simpleInline.decompiled @@ -1,7 +1,5 @@ /** Decompiled from out/posTestFromTasty/pos/simpleInline/Foo.class */ class Foo() { inline def foo: scala.Int = (9: scala.Int) - def bar: scala.Int = { // inlined - (9: scala.Int) - } + def bar: scala.Int = (9: scala.Int) } \ No newline at end of file diff --git a/tests/pos/simpleMatchCase.decompiled b/tests/pos/simpleMatchCase.decompiled index 4b7727b34ebe..265134cc19e4 100644 --- a/tests/pos/simpleMatchCase.decompiled +++ b/tests/pos/simpleMatchCase.decompiled @@ -1,10 +1,8 @@ /** Decompiled from out/posTestFromTasty/pos/simpleMatchCase/Foo.class */ class Foo() { - def foo: scala.Unit = { - "c" match { - case x => - scala.Predef.println("a") - scala.Predef.println("b") - } + def foo: scala.Unit = "c" match { + case x => + scala.Predef.println("a") + scala.Predef.println("b") } } diff --git a/tests/pos/simpleWhile.decompiled b/tests/pos/simpleWhile.decompiled index 269c17ab1aa3..12c319714704 100644 --- a/tests/pos/simpleWhile.decompiled +++ b/tests/pos/simpleWhile.decompiled @@ -2,8 +2,6 @@ class Foo() { def foo: scala.Unit = { var i: scala.Int = 1 - while (i.!=(0)) { - i = 0 - } + while (i.!=(0)) i = 0 } } \ No newline at end of file diff --git a/tests/pos/t3869.decompiled b/tests/pos/t3869.decompiled index ec1fe8ed28f5..873660e2f03f 100644 --- a/tests/pos/t3869.decompiled +++ b/tests/pos/t3869.decompiled @@ -1,7 +1,5 @@ /** Decompiled from out/posTestFromTasty/pos/t3869/Test.class */ object Test { def f: scala.Unit = try return () finally while (true) () - def main(args: scala.Array[scala.Predef.String]): scala.Unit = { - Test.f - } + def main(args: scala.Array[scala.Predef.String]): scala.Unit = Test.f } diff --git a/tests/pos/t704.decompiled b/tests/pos/t704.decompiled index 64f50b9e9d27..f1cd2fce613a 100644 --- a/tests/pos/t704.decompiled +++ b/tests/pos/t704.decompiled @@ -16,11 +16,8 @@ trait E() extends java.lang.Object with D { val x1: scala.AnyRef = E.this.get_xxxx scala.Console.println(y) } - - { - yyyy - () - } + yyyy + () } } /** Decompiled from out/posTestFromTasty/pos/t704/Go.class */ diff --git a/tests/run-with-compiler/quote-impure-by-name.check b/tests/run-with-compiler/quote-impure-by-name.check index d29945c196fa..6616ccfa5430 100644 --- a/tests/run-with-compiler/quote-impure-by-name.check +++ b/tests/run-with-compiler/quote-impure-by-name.check @@ -1,3 +1 @@ -1 + {{ // inlined - Index.zero["bar", scala.Tuple2["baz", scala.Unit]] -}} +1 + {Index.zero["bar", scala.Tuple2["baz", scala.Unit]]} diff --git a/tests/run-with-compiler/quote-nested-3.check b/tests/run-with-compiler/quote-nested-3.check index 1dc1b00982a4..a441ab9cc3e3 100644 --- a/tests/run-with-compiler/quote-nested-3.check +++ b/tests/run-with-compiler/quote-nested-3.check @@ -2,6 +2,5 @@ type T = scala.Predef.String val x: java.lang.String = "foo" val z: T = x - () (x: java.lang.String) } diff --git a/tests/run-with-compiler/quote-show-blocks-raw.check b/tests/run-with-compiler/quote-show-blocks-raw.check deleted file mode 100644 index 2e67f4f8c2a5..000000000000 --- a/tests/run-with-compiler/quote-show-blocks-raw.check +++ /dev/null @@ -1,36 +0,0 @@ -{ - scala.Predef.println(1) - - { - scala.Predef.println(2) - - { - scala.Predef.println(3) - - { - scala.Predef.println(4) - - { - scala.Predef.println(5) - () - } - } - } - } -} -{ - { - { - { - { - () - scala.Predef.println(5) - } - scala.Predef.println(4) - } - scala.Predef.println(3) - } - scala.Predef.println(2) - } - scala.Predef.println(1) -} diff --git a/tests/run-with-compiler/quote-show-blocks-raw.scala b/tests/run-with-compiler/quote-show-blocks-raw.scala deleted file mode 100644 index 20c142f4144e..000000000000 --- a/tests/run-with-compiler/quote-show-blocks-raw.scala +++ /dev/null @@ -1,25 +0,0 @@ - -import scala.quoted.Toolbox.Default._ -import scala.quoted.Toolbox - -import scala.quoted._ - -object Test { - def main(args: Array[String]): Unit = { - implicit val settings: Toolbox.Settings = Toolbox.Settings.make(showRawTree = 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/shonan-hmm.check b/tests/run-with-compiler/shonan-hmm.check index 1d524b5c4fc6..29b8c12e99ec 100644 --- a/tests/run-with-compiler/shonan-hmm.check +++ b/tests/run-with-compiler/shonan-hmm.check @@ -93,7 +93,6 @@ List(25, 30, 20, 43, 44) }) array } - ((vout: scala.Array[scala.Int], v: scala.Array[scala.Int]) => { if (5.!=(vout.length)) throw new scala.IndexOutOfBoundsException("5") else () if (5.!=(v.length)) throw new scala.IndexOutOfBoundsException("5") else () @@ -157,7 +156,6 @@ List(25, 30, 20, 43, 44) }) array } - ((vout: scala.Array[scala.Int], v: scala.Array[scala.Int]) => { if (5.!=(vout.length)) throw new scala.IndexOutOfBoundsException("5") else () if (5.!=(v.length)) throw new scala.IndexOutOfBoundsException("5") else () @@ -221,7 +219,6 @@ List(25, 30, 20, 43, 44) }) array } - ((vout: scala.Array[scala.Int], v: scala.Array[scala.Int]) => { if (5.!=(vout.length)) throw new scala.IndexOutOfBoundsException("5") else () if (5.!=(v.length)) throw new scala.IndexOutOfBoundsException("5") else () @@ -281,7 +278,6 @@ List(25, 30, 20, 43, 44) array.update(4, 5) array } - ((vout: scala.Array[scala.Int], v: scala.Array[scala.Int]) => { if (5.!=(vout.length)) throw new scala.IndexOutOfBoundsException("5") else () if (5.!=(v.length)) throw new scala.IndexOutOfBoundsException("5") else () diff --git a/tests/run/literals.decompiled b/tests/run/literals.decompiled index 5ede2bfa50ec..0515ab0223c7 100644 --- a/tests/run/literals.decompiled +++ b/tests/run/literals.decompiled @@ -30,16 +30,10 @@ object Test { scala.Predef.print("test ".+(name)) try { val actual: a = closure - if (actual.==(expected)) { - scala.Predef.print(" was successful") - } else { - scala.Predef.print(" failed: expected ".+(expected).+(", found ").+(actual)) - } + if (actual.==(expected)) scala.Predef.print(" was successful") else scala.Predef.print(" failed: expected ".+(expected).+(", found ").+(actual)) } catch { case exception: scala.Throwable => - { - scala.Predef.print(" raised exception ".+(exception)) - } + scala.Predef.print(" raised exception ".+(exception)) } scala.Predef.println() }