diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 32861249c800..bc0569f7c75a 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -7,11 +7,12 @@ 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 +import scala.reflect.ClassTag object PickledQuotes { import tpd._ @@ -34,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 } @@ -42,26 +55,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/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/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 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 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