From 40b200a3e545fab64f97b0e66158e88967b24c79 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 17 May 2018 08:23:22 +0200 Subject: [PATCH] Pickle quotes directly as expressions in TASTY * We avoid having to do owner changes after unpickling * The pickled code is slightly smaller --- .../dotc/core/quoted/PickledQuotes.scala | 34 +++---------------- .../dotc/core/tasty/DottyUnpickler.scala | 3 ++ .../tools/dotc/core/tasty/TreeUnpickler.scala | 9 ++++- tests/run-with-compiler/quote-owners-2.check | 14 ++++++++ tests/run-with-compiler/quote-owners-2.scala | 25 ++++++++++++++ tests/run-with-compiler/quote-owners.check | 9 +++++ tests/run-with-compiler/quote-owners.scala | 22 ++++++++++++ tests/run-with-compiler/quote-run-large.scala | 5 +++ 8 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 tests/run-with-compiler/quote-owners-2.check create mode 100644 tests/run-with-compiler/quote-owners-2.scala create mode 100644 tests/run-with-compiler/quote-owners.check create mode 100644 tests/run-with-compiler/quote-owners.scala diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 45fed5697fc7..717dc343e201 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -46,8 +46,7 @@ object PickledQuotes { if (ctx.reporter.hasErrors) Nil else { assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'(~x)` which should be optimized to `x` - val encapsulated = encapsulateQuote(tree) - val pickled = pickle(encapsulated) + val pickled = pickle(tree) TastyString.pickle(pickled) } } @@ -75,37 +74,13 @@ object PickledQuotes { /** Unpickle the tree contained in the TastyExpr */ private def unpickleExpr(expr: TastyExpr[_])(implicit ctx: Context): Tree = { val tastyBytes = TastyString.unpickle(expr.tasty) - val unpickled = unpickle(tastyBytes, expr.args) - unpickled match { - case PackageDef(_, (vdef: ValDef) :: Nil) => - vdef.rhs.changeOwner(vdef.symbol, ctx.owner) - } + unpickle(tastyBytes, expr.args) } /** Unpickle the tree contained in the TastyType */ private def unpickleType(ttpe: TastyType[_])(implicit ctx: Context): Tree = { val tastyBytes = TastyString.unpickle(ttpe.tasty) - val unpickled = unpickle(tastyBytes, ttpe.args) - unpickled match { - case PackageDef(_, (vdef: ValDef) :: Nil) => - vdef.rhs.asInstanceOf[TypeApply].args.head - .changeOwner(vdef.symbol, ctx.owner) - } - } - - /** Encapsulate the tree in a top level `val` or `type` - * `` ==> `package _root_ { val $quote: Any = }` - * or - * `` ==> `package _root_ { val $typeQuote: Any = null.asInstanceOf[] }` - */ - private def encapsulateQuote(tree: Tree)(implicit ctx: Context): Tree = { - val name = (if (tree.isTerm) "$quote" else "$typeQuote").toTermName - val sym = ctx.newSymbol(ctx.owner, name, Synthetic, defn.AnyType, coord = tree.pos) - val encoded = - if (tree.isTerm) tree - else Literal(Constant(null)).select(nme.asInstanceOf_).appliedToTypeTrees(tree :: Nil) - val quoted = ValDef(sym, encoded).withPos(tree.pos) - PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], quoted :: Nil).withPos(tree.pos) + unpickle(tastyBytes, ttpe.args) } // TASTY picklingtests/pos/quoteTest.scala @@ -135,8 +110,7 @@ object PickledQuotes { /** Unpickle TASTY bytes into it's tree */ private def unpickle(bytes: Array[Byte], splices: Seq[Any])(implicit ctx: Context): Tree = { val unpickler = new TastyUnpickler(bytes, splices) - unpickler.enter(roots = Set(defn.RootPackage)) - val tree = unpickler.tree + val tree = unpickler.unpickleExpr() if (pickling ne noPrinter) { println(i"**** unpickled quote for \n${tree.show}") new TastyPrinter(bytes).printContents() diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 29ae7cca14a7..5dc92ee916df 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -46,6 +46,9 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded with t def enter(roots: Set[SymDenotation])(implicit ctx: Context): Unit = treeUnpickler.enterTopLevel(roots) + def unpickleExpr()(implicit ctx: Context): Tree = + treeUnpickler.unpickleExpr() + protected def treeSectionUnpickler(posUnpicklerOpt: Option[PositionUnpickler]): TreeSectionUnpickler = { new TreeSectionUnpickler(posUnpicklerOpt) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 2d7ae573d48f..620dd44f84e9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -73,11 +73,18 @@ class TreeUnpickler(reader: TastyReader, */ def enterTopLevel(roots: Set[SymDenotation])(implicit ctx: Context): Unit = { this.roots = roots - var rdr = new TreeReader(reader).fork + val rdr = new TreeReader(reader).fork ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr) rdr.indexStats(reader.endAddr) } + def unpickleExpr()(implicit ctx: Context): Tree = { + this.roots = Set(ctx.owner) + val rdr = new TreeReader(reader).fork + ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr) + rdr.readTerm() + } + /** The unpickled trees */ def unpickle()(implicit ctx: Context): List[Tree] = { assert(roots != null, "unpickle without previous enterTopLevel") diff --git a/tests/run-with-compiler/quote-owners-2.check b/tests/run-with-compiler/quote-owners-2.check new file mode 100644 index 000000000000..fee34077c6f9 --- /dev/null +++ b/tests/run-with-compiler/quote-owners-2.check @@ -0,0 +1,14 @@ +3 +{ + def ff: Int = + { + val a: List[Int] = + { + type T = List[Int] + val b: T = Nil.::[Int](3) + b: List[Int] + } + a.head: Int + } + ff: Int +} diff --git a/tests/run-with-compiler/quote-owners-2.scala b/tests/run-with-compiler/quote-owners-2.scala new file mode 100644 index 000000000000..7e2d11e9b374 --- /dev/null +++ b/tests/run-with-compiler/quote-owners-2.scala @@ -0,0 +1,25 @@ + +import quoted._ +import dotty.tools.dotc.quoted.Toolbox._ + +object Test { + def main(args: Array[String]): Unit = { + val q = f(g(Type.IntTag)) + println(q.run) + println(q.show) + } + + def f(t: Type[List[Int]]): Expr[Int] = '{ + def ff: Int = { + val a: ~t = { + type T = ~t + val b: T = 3 :: Nil + b + } + a.head + } + ff + } + + def g[T](a: Type[T]): Type[List[T]] = '[List[~a]] +} diff --git a/tests/run-with-compiler/quote-owners.check b/tests/run-with-compiler/quote-owners.check new file mode 100644 index 000000000000..8b1f473d369a --- /dev/null +++ b/tests/run-with-compiler/quote-owners.check @@ -0,0 +1,9 @@ +9 +{ + def ff: Int = + { + val a: Int = 9 + a.+(0) + } + ff: Int +} diff --git a/tests/run-with-compiler/quote-owners.scala b/tests/run-with-compiler/quote-owners.scala new file mode 100644 index 000000000000..1ccadf592d0a --- /dev/null +++ b/tests/run-with-compiler/quote-owners.scala @@ -0,0 +1,22 @@ +import quoted._ +import dotty.tools.dotc.quoted.Toolbox._ + +object Test { + def main(args: Array[String]): Unit = { + val q = f + println(q.run) + println(q.show) + } + + def f: Expr[Int] = '{ + def ff: Int = { + ~g + } + ff + } + + def g: Expr[Int] = '{ + val a = 9 + a + 0 + } +} diff --git a/tests/run-with-compiler/quote-run-large.scala b/tests/run-with-compiler/quote-run-large.scala index 43f02704700d..46e90e29a3b1 100644 --- a/tests/run-with-compiler/quote-run-large.scala +++ b/tests/run-with-compiler/quote-run-large.scala @@ -51,6 +51,11 @@ object Test { def foo42: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x def foo43: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x def foo44: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + def foo45: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + def foo46: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + def foo47: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + def foo48: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + def foo49: Int = x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x } new Foo(5)