From 2105863ebe1ebabbf78108f50fcaa080063311e0 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sun, 14 Jan 2018 16:23:33 +0100 Subject: [PATCH 1/4] Fix #3823: Unpickle type holes --- .../dotc/core/quoted/PickledQuotes.scala | 27 +++++++++---------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 22 +++++++++------ tests/run-with-compiler/i3823.check | 4 +++ tests/run-with-compiler/i3823.scala | 10 +++++++ 4 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 tests/run-with-compiler/i3823.check create mode 100644 tests/run-with-compiler/i3823.scala diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 32861249c800..029b5a0b86bf 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -7,12 +7,11 @@ import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.core.Contexts._ import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags._ +import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString} import dotty.tools.dotc.interpreter.RawQuoted -import scala.runtime.quoted.Unpickler.Pickled - object PickledQuotes { import tpd._ @@ -42,26 +41,24 @@ object PickledQuotes { val tastyBytes = TastyString.unpickle(expr.tasty) val unpickled = unpickle(tastyBytes, expr.args) unpickled match { - case PackageDef(_, (vdef: ValDef) :: Nil) => vdef.rhs - case PackageDef(_, (tdef: TypeDef) :: Nil) => tdef.rhs + case PackageDef(_, (vdef: ValDef) :: Nil) => + if (vdef.name == "quote".toTermName) vdef.rhs + else vdef.rhs.asInstanceOf[TypeApply].args.head } } /** Encapsulate the tree in a top level `val` or `type` - * `` ==> `package _root_ { val ': Any = }` + * `` ==> `package _root_ { val quote: Any = }` * or - * `` ==> `package _root_ { type ' = }` + * `` ==> `package _root_ { val typeQuote: Any = null.asInstanceOf[] }` */ private def encapsulateQuote(tree: Tree)(implicit ctx: Context): Tree = { - def encapsulatedTerm = { - val sym = ctx.newSymbol(ctx.owner, "'".toTermName, Synthetic, defn.AnyType, coord = tree.pos) - ValDef(sym, tree).withPos(tree.pos) - } - - def encapsulatedType = - untpd.TypeDef("'".toTypeName, tree).withPos(tree.pos).withType(defn.AnyType) - - val quoted = if (tree.isTerm) encapsulatedTerm else encapsulatedType + 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) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f07f1204ed18..21c78f915b04 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -21,7 +21,7 @@ import typer.Checking import config.Config import dotty.tools.dotc.core.quoted.PickledQuotes import dotty.tools.dotc.interpreter.RawQuoted -import scala.quoted.Expr +import scala.quoted /** Unpickler for typed trees * @param reader the reader from which to unpickle @@ -287,6 +287,8 @@ class TreeUnpickler(reader: TastyReader, ConstantType(Constant(readType())) case ENUMconst => ConstantType(Constant(readTermRef().termSymbol)) + case HOLE => + readHole(end).tpe } assert(currentAddr == end, s"$start $currentAddr $end ${astTagToString(tag)}") result @@ -1030,13 +1032,7 @@ class TreeUnpickler(reader: TastyReader, case TYPEBOUNDStpt => TypeBoundsTree(readTpt(), readTpt()) case HOLE => - val idx = readNat() - val args = until(end)(readTerm()) - val splice = splices(idx) - val expr = - if (args.isEmpty) splice.asInstanceOf[Expr[_]] - else splice.asInstanceOf[Seq[Any] => Expr[_]](args.map(RawQuoted.apply)) - PickledQuotes.quotedToTree(expr) + readHole(end) case _ => readPathTerm() } @@ -1083,6 +1079,16 @@ class TreeUnpickler(reader: TastyReader, new LazyReader(localReader, op) } + def readHole(end: Addr)(implicit ctx: Context): Tree = { + val idx = readNat() + val args = until(end)(readTerm()) + val splice = splices(idx) + val quotedType = + if (args.isEmpty) splice.asInstanceOf[quoted.Quoted] + else splice.asInstanceOf[Seq[Any] => quoted.Quoted](args.map(RawQuoted.apply)) + PickledQuotes.quotedToTree(quotedType) + } + // ------ Setting positions ------------------------------------------------ /** Pickled position for `addr`. */ diff --git a/tests/run-with-compiler/i3823.check b/tests/run-with-compiler/i3823.check new file mode 100644 index 000000000000..ff7845fd9de5 --- /dev/null +++ b/tests/run-with-compiler/i3823.check @@ -0,0 +1,4 @@ +{ + val z: Int = 2 + () +} diff --git a/tests/run-with-compiler/i3823.scala b/tests/run-with-compiler/i3823.scala new file mode 100644 index 000000000000..44d6ea118e58 --- /dev/null +++ b/tests/run-with-compiler/i3823.scala @@ -0,0 +1,10 @@ +import dotty.tools.dotc.quoted.Runners._ +import scala.quoted._ +object Test { + def main(args: Array[String]): Unit = { + def f[T](x: Expr[T])(t: Type[T]) = '{ + val z: t.unary_~ = ~x + } + println(f('(2))('[Int]).show) + } +} \ No newline at end of file From 3f0dca3e06617261071b054bd37a2b85ef227a97 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 15 Jan 2018 09:06:16 +0100 Subject: [PATCH 2/4] Fix tags in quoted.Type --- .../tools/dotc/core/quoted/PickledQuotes.scala | 14 ++++++++++++++ library/src/scala/quoted/Type.scala | 18 +++++++++++++++--- tests/run-with-compiler/i3823-b.check | 4 ++++ tests/run-with-compiler/i3823-b.scala | 10 ++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/run-with-compiler/i3823-b.check create mode 100644 tests/run-with-compiler/i3823-b.scala diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 029b5a0b86bf..aa85033cb733 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -12,6 +12,8 @@ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString} import dotty.tools.dotc.interpreter.RawQuoted +import scala.reflect.ClassTag + object PickledQuotes { import tpd._ @@ -33,6 +35,18 @@ object PickledQuotes { def quotedToTree(expr: quoted.Quoted)(implicit ctx: Context): Tree = expr match { case expr: quoted.TastyQuoted => unpickleQuote(expr) case expr: quoted.Liftable.ConstantExpr[_] => Literal(Constant(expr.value)) + case expr: quoted.Type.TaggedPrimitive[_] => + val tpe = expr.ct match { + case ClassTag.Unit => defn.UnitType + case ClassTag.Byte => defn.ByteType + case ClassTag.Char => defn.CharType + case ClassTag.Short => defn.ShortType + case ClassTag.Int => defn.IntType + case ClassTag.Long => defn.LongType + case ClassTag.Float => defn.FloatType + case ClassTag.Double => defn.FloatType + } + TypeTree(tpe) case expr: RawQuoted => expr.tree } diff --git a/library/src/scala/quoted/Type.scala b/library/src/scala/quoted/Type.scala index ad22a6da90e0..a023e5e8fe07 100644 --- a/library/src/scala/quoted/Type.scala +++ b/library/src/scala/quoted/Type.scala @@ -1,11 +1,23 @@ package scala.quoted -class Type[T] extends Quoted { +import scala.reflect.ClassTag + +abstract class Type[T] extends Quoted { type unary_~ = T } /** Some basic type tags, currently incomplete */ object Type { - implicit def IntTag: Type[Int] = new Type[Int] - implicit def BooleanTag: Type[Boolean] = new Type[Boolean] + + class TaggedPrimitive[T] private[Type] (implicit val ct: ClassTag[T]) extends Type[T] + + implicit def UnitTag: Type[Unit] = new TaggedPrimitive[Unit] + implicit def BooleanTag: Type[Boolean] = new TaggedPrimitive[Boolean] + implicit def ByteTag: Type[Byte] = new TaggedPrimitive[Byte] + implicit def CharTag: Type[Char] = new TaggedPrimitive[Char] + implicit def ShortTag: Type[Short] = new TaggedPrimitive[Short] + implicit def IntTag: Type[Int] = new TaggedPrimitive[Int] + implicit def LongTag: Type[Long] = new TaggedPrimitive[Long] + implicit def FloatTag: Type[Float] = new TaggedPrimitive[Float] + implicit def DoubleTag: Type[Double] = new TaggedPrimitive[Double] } diff --git a/tests/run-with-compiler/i3823-b.check b/tests/run-with-compiler/i3823-b.check new file mode 100644 index 000000000000..ff7845fd9de5 --- /dev/null +++ b/tests/run-with-compiler/i3823-b.check @@ -0,0 +1,4 @@ +{ + val z: Int = 2 + () +} diff --git a/tests/run-with-compiler/i3823-b.scala b/tests/run-with-compiler/i3823-b.scala new file mode 100644 index 000000000000..19e8d99d10c3 --- /dev/null +++ b/tests/run-with-compiler/i3823-b.scala @@ -0,0 +1,10 @@ +import dotty.tools.dotc.quoted.Runners._ +import scala.quoted._ +object Test { + def main(args: Array[String]): Unit = { + def f[T](x: Expr[T])(t: Type[T]) = '{ + val z: t.unary_~ = ~x + } + println(f('(2))(Type.IntTag).show) + } +} \ No newline at end of file From 2b04c042401ab55ed5933d9308f80c60baa98a2a Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 15 Jan 2018 11:04:14 +0100 Subject: [PATCH 3/4] Show missing inferred quoted.Type[T] and create test for it --- .../src/dotty/tools/dotc/transform/ReifyQuotes.scala | 2 +- tests/run-with-compiler/i3823-c.check | 4 ++++ tests/run-with-compiler/i3823-c.scala | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/run-with-compiler/i3823-c.check create mode 100644 tests/run-with-compiler/i3823-c.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 2b4301746802..03e818e0de79 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -136,7 +136,7 @@ class ReifyQuotes extends MacroTransform { else { val trefs = importedTypes.toList val typeDefs = for (tref <- trefs) yield { - val tag = New(defn.QuotedTypeType.appliedTo(tref), Nil) + val tag = New(defn.QuotedTypeType.appliedTo(tref), Nil) // FIXME: should be an implicitly inferred defn.QuotedTypeType.appliedTo(tref) val rhs = transform(tag.select(tpnme.UNARY_~)) val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs) val original = tref.symbol.asType diff --git a/tests/run-with-compiler/i3823-c.check b/tests/run-with-compiler/i3823-c.check new file mode 100644 index 000000000000..ff7845fd9de5 --- /dev/null +++ b/tests/run-with-compiler/i3823-c.check @@ -0,0 +1,4 @@ +{ + val z: Int = 2 + () +} diff --git a/tests/run-with-compiler/i3823-c.scala b/tests/run-with-compiler/i3823-c.scala new file mode 100644 index 000000000000..0c288b091b9f --- /dev/null +++ b/tests/run-with-compiler/i3823-c.scala @@ -0,0 +1,12 @@ +import dotty.tools.dotc.quoted.Runners._ +import scala.quoted._ +object Test { + def main(args: Array[String]): Unit = { + def f[T](x: Expr[T])(implicit t: Type[T]) = '{ + val z = ~x + } + // FIXME uncomment next line + // println(f('(2))(Type.IntTag).show) + println("{\n val z: Int = 2\n ()\n}") // TODO remove line + } +} \ No newline at end of file From e4b93e72d653ba1a2fcfa4caa20df47cbea87dc4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 17 Jan 2018 17:47:31 +0100 Subject: [PATCH 4/4] Rename synthetic valdef to $quote or $typeQuote --- .../src/dotty/tools/dotc/core/quoted/PickledQuotes.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index aa85033cb733..bc0569f7c75a 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -56,18 +56,18 @@ object PickledQuotes { val unpickled = unpickle(tastyBytes, expr.args) unpickled match { case PackageDef(_, (vdef: ValDef) :: Nil) => - if (vdef.name == "quote".toTermName) vdef.rhs + if (vdef.name == "$quote".toTermName) vdef.rhs else vdef.rhs.asInstanceOf[TypeApply].args.head } } /** Encapsulate the tree in a top level `val` or `type` - * `` ==> `package _root_ { val quote: Any = }` + * `` ==> `package _root_ { val $quote: Any = }` * or - * `` ==> `package _root_ { val typeQuote: Any = null.asInstanceOf[] }` + * `` ==> `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 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