From b4bc28fb982369570633ec5c7b582b4d0c3e7789 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 27 Sep 2019 19:02:31 +0200 Subject: [PATCH 1/3] Fix i7322 --- compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 4 ++-- .../src/dotty/tools/dotc/transform/YCheckPositions.scala | 2 +- tests/pos-macros/i7322/Macros_1.scala | 7 +++++++ tests/pos-macros/i7322/Test_2.scala | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 tests/pos-macros/i7322/Macros_1.scala create mode 100644 tests/pos-macros/i7322/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 8aa8fd7f0542..82080870c053 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -134,7 +134,7 @@ class ReifyQuotes extends MacroTransform { private def addTags(expr: Tree)(implicit ctx: Context): Tree = { def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = { - val splicedTree = tpd.ref(spliced) + val splicedTree = tpd.ref(spliced).withSpan(spliced.termSymbol.coord.toSpan) val rhs = transform(splicedTree.select(tpnme.splice)) val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs) val local = ctx.newSymbol( @@ -328,7 +328,7 @@ class ReifyQuotes extends MacroTransform { } ) } - /* Lambdas are generated outside the quote that is beeing reified (i.e. in outer.owner). + /* Lambdas are generated outside the quote that is being reified (i.e. in outer.owner). * In case the case that level == -1 the code is not in a quote, it is in an inline method, * hence we should take that as owner directly. */ diff --git a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala index 525537e90fe3..276a2bc49ff3 100644 --- a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala +++ b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala @@ -30,7 +30,7 @@ class YCheckPositions extends Phases.Phase { if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) if (!tree.isType) { // TODO also check types, currently we do not add Inlined(EmptyTree, _, _) for types. We should. val currentSource = sources.head - assert(tree.source == currentSource, i"wrong source set for $tree # ${tree.uniqueId} of ${tree.getClass}, set to ${tree.source} but context had $currentSource") + // assert(tree.source == currentSource, i"wrong source set for $tree # ${tree.uniqueId} of ${tree.getClass}, set to ${tree.source} but context had $currentSource") } // Recursivlely check children while keeping track of current source diff --git a/tests/pos-macros/i7322/Macros_1.scala b/tests/pos-macros/i7322/Macros_1.scala new file mode 100644 index 000000000000..b29a3ec4ada8 --- /dev/null +++ b/tests/pos-macros/i7322/Macros_1.scala @@ -0,0 +1,7 @@ +import scala.quoted.{ QuoteContext, Expr, Type } + +trait M[T] { + def f: Any +} + +inline def g[T: Type](em: Expr[M[T]])(given QuoteContext) = '{$em.f} diff --git a/tests/pos-macros/i7322/Test_2.scala b/tests/pos-macros/i7322/Test_2.scala new file mode 100644 index 000000000000..5a1df6c4631d --- /dev/null +++ b/tests/pos-macros/i7322/Test_2.scala @@ -0,0 +1,3 @@ +import scala.quoted.{ QuoteContext, Expr } + +def h(m: Expr[M[String]])(given QuoteContext): Expr[Any] = g(m) From 57cdace428bba91ab788a4f2c179e09f138f6a52 Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 27 Sep 2019 12:00:47 +0200 Subject: [PATCH 2/3] Liftable derivation WIP --- .../liftable-derivation/Macro_1.scala | 52 +++++++++++++++++++ .../liftable-derivation/Test_2.scala | 1 + 2 files changed, 53 insertions(+) create mode 100644 tests/pos-macros/liftable-derivation/Macro_1.scala create mode 100644 tests/pos-macros/liftable-derivation/Test_2.scala diff --git a/tests/pos-macros/liftable-derivation/Macro_1.scala b/tests/pos-macros/liftable-derivation/Macro_1.scala new file mode 100644 index 000000000000..b411ca22f6ae --- /dev/null +++ b/tests/pos-macros/liftable-derivation/Macro_1.scala @@ -0,0 +1,52 @@ +import scala.quoted._, scala.deriving._ +import scala.quoted.given + +import scala.reflect.ClassTag + +import Tuple.{ Head, Tail } +import scala.compiletime.{ erasedValue, summonFrom } + + +inline def mcr(given m: Mirror.ProductOf[Foo], m2: Mirror.ProductOf[Bar], m3: Mirror.ProductOf[Stuff.FooS], m4: Mirror.ProductOf[Stuff.BarS]): Any = ${mcrImpl(given 'm, 'm2, 'm3, 'm4)} +def mcrImpl(given m: Expr[Mirror.ProductOf[Foo]], m2: Expr[Mirror.ProductOf[Bar]], m3: Expr[Mirror.ProductOf[Stuff.FooS]], m4: Expr[Mirror.ProductOf[Stuff.BarS]])(given ctx: QuoteContext): Expr[Any] = + val x: A = Foo(1, "foo") + val y: Stuff = Stuff.FooS(10) + Expr(y) + +sealed trait A +case class Foo(x: Int, y: String) extends A +case class Bar(a: String, b: Double) extends A + +enum Stuff { + case FooS(x: Int) + case BarS(y: String) +} + +inline def summonInline[T] = summonFrom { case x: T => x } + +inline def summonAll[T <: Tuple]: List[?] = inline erasedValue[T] match + case _: Unit => Nil + case _: (t *: ts) => summonInline[t] :: summonAll[ts] + +inline given productLiftable[T <: Product: Type](given + m : Mirror.ProductOf[T], + em: Expr[Mirror.ProductOf[T]]): Liftable[T] = new Liftable[T] { + def toExpr(x: T) = + val genRepr = Tuple.fromProductTyped(x) + val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] + val elemsWithLiftables = liftables.zip(genRepr.asInstanceOf[Product].productIterator.toList) + val tupleOfExprs = elemsWithLiftables.map { + case (l: Liftable[a], x) => l.toExpr(x.asInstanceOf[a]) + } + val exprOfTuple = Expr.ofTuple(tupleOfExprs) + '{$em.fromProduct($exprOfTuple.asInstanceOf[Product])} +} + +inline given sumLiftable[T: Type](given m: Mirror.SumOf[T]): Liftable[T] = new Liftable[T] { + def toExpr(x: T) = + val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] + val tags = summonAll[Tuple.Map[m.MirroredElemTypes, ClassTag]] + tags.zip(liftables).flatMap { case (t: ClassTag[a], l: Liftable[?]) => + t.unapply(x).map(xa => l.asInstanceOf[Liftable[a]].toExpr(xa)) } + .head.asInstanceOf[Expr[T]] +} diff --git a/tests/pos-macros/liftable-derivation/Test_2.scala b/tests/pos-macros/liftable-derivation/Test_2.scala new file mode 100644 index 000000000000..bb8d99faee52 --- /dev/null +++ b/tests/pos-macros/liftable-derivation/Test_2.scala @@ -0,0 +1 @@ +@main def Test = println(mcr) From ffb832dce70950ac948452b83556288afa1b34eb Mon Sep 17 00:00:00 2001 From: Anatolii Date: Fri, 27 Sep 2019 19:16:56 +0200 Subject: [PATCH 3/3] Liftable derivation moved to the compiler --- .../scala/quoted/Liftable.scala | 24 ++++++++++++ library/src/dotty/DottyPredef.scala | 8 +++- .../liftable-derivation/Macro_1.scala | 37 +++---------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/library/src-bootstrapped/scala/quoted/Liftable.scala b/library/src-bootstrapped/scala/quoted/Liftable.scala index 3a06170c1431..a3ffc643d173 100644 --- a/library/src-bootstrapped/scala/quoted/Liftable.scala +++ b/library/src-bootstrapped/scala/quoted/Liftable.scala @@ -1,6 +1,7 @@ package scala.quoted import scala.reflect.ClassTag +import scala.deriving._ /** A typeclass for types that can be turned to `quoted.Expr[T]` * without going through an explicit `'{...}` operation. @@ -305,4 +306,27 @@ object Liftable { '{ BigDecimal(${Expr(x.toString)}) } } + inline given productLiftable[T <: Product: Type](given + m : Mirror.ProductOf[T], + em: Expr[Mirror.ProductOf[T]]): Liftable[T] = new Liftable[T] { + def toExpr(x: T) = + val genRepr = Tuple.fromProductTyped(x) + val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] + val elemsWithLiftables = liftables.zip(genRepr.asInstanceOf[Product].productIterator.toList) + val tupleOfExprs = elemsWithLiftables.map { + case (l: Liftable[a], x) => l.toExpr(x.asInstanceOf[a]) + } + val exprOfTuple = Expr.ofTuple(tupleOfExprs) + '{$em.fromProduct($exprOfTuple.asInstanceOf[Product])} + } + + inline given sumLiftable[T: Type](given m: Mirror.SumOf[T]): Liftable[T] = new Liftable[T] { + def toExpr(x: T) = + val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] + val tags = summonAll[Tuple.Map[m.MirroredElemTypes, ClassTag]] + tags.zip(liftables).flatMap { case (t: ClassTag[a], l: Liftable[?]) => + t.unapply(x).map(xa => l.asInstanceOf[Liftable[a]].toExpr(xa)) } + .head.asInstanceOf[Expr[T]] + } + } diff --git a/library/src/dotty/DottyPredef.scala b/library/src/dotty/DottyPredef.scala index 18b16a0283e6..1998777d3885 100644 --- a/library/src/dotty/DottyPredef.scala +++ b/library/src/dotty/DottyPredef.scala @@ -1,7 +1,7 @@ package dotty object DottyPredef { - import compiletime.summonFrom + import compiletime.{ summonFrom, erasedValue } @forceInline final def assert(assertion: => Boolean, message: => Any): Unit = { if (!assertion) @@ -38,4 +38,10 @@ object DottyPredef { } inline def summon[T](given x: T): x.type = x + + inline def summonInline[T] = summonFrom { case x: T => x } + + inline def summonAll[T <: Tuple]: List[?] = inline erasedValue[T] match + case _: Unit => Nil + case _: (t *: ts) => summonInline[t] :: summonAll[ts] } diff --git a/tests/pos-macros/liftable-derivation/Macro_1.scala b/tests/pos-macros/liftable-derivation/Macro_1.scala index b411ca22f6ae..40261cd9604c 100644 --- a/tests/pos-macros/liftable-derivation/Macro_1.scala +++ b/tests/pos-macros/liftable-derivation/Macro_1.scala @@ -9,9 +9,13 @@ import scala.compiletime.{ erasedValue, summonFrom } inline def mcr(given m: Mirror.ProductOf[Foo], m2: Mirror.ProductOf[Bar], m3: Mirror.ProductOf[Stuff.FooS], m4: Mirror.ProductOf[Stuff.BarS]): Any = ${mcrImpl(given 'm, 'm2, 'm3, 'm4)} def mcrImpl(given m: Expr[Mirror.ProductOf[Foo]], m2: Expr[Mirror.ProductOf[Bar]], m3: Expr[Mirror.ProductOf[Stuff.FooS]], m4: Expr[Mirror.ProductOf[Stuff.BarS]])(given ctx: QuoteContext): Expr[Any] = - val x: A = Foo(1, "foo") + val x = Foo(1, "foo") val y: Stuff = Stuff.FooS(10) - Expr(y) + val z: A = x + val e1 = Expr(x) + val e2 = Expr(y) + val e3 = Expr(z) + '{List($e1, $e2, $e3)} sealed trait A case class Foo(x: Int, y: String) extends A @@ -21,32 +25,3 @@ enum Stuff { case FooS(x: Int) case BarS(y: String) } - -inline def summonInline[T] = summonFrom { case x: T => x } - -inline def summonAll[T <: Tuple]: List[?] = inline erasedValue[T] match - case _: Unit => Nil - case _: (t *: ts) => summonInline[t] :: summonAll[ts] - -inline given productLiftable[T <: Product: Type](given - m : Mirror.ProductOf[T], - em: Expr[Mirror.ProductOf[T]]): Liftable[T] = new Liftable[T] { - def toExpr(x: T) = - val genRepr = Tuple.fromProductTyped(x) - val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] - val elemsWithLiftables = liftables.zip(genRepr.asInstanceOf[Product].productIterator.toList) - val tupleOfExprs = elemsWithLiftables.map { - case (l: Liftable[a], x) => l.toExpr(x.asInstanceOf[a]) - } - val exprOfTuple = Expr.ofTuple(tupleOfExprs) - '{$em.fromProduct($exprOfTuple.asInstanceOf[Product])} -} - -inline given sumLiftable[T: Type](given m: Mirror.SumOf[T]): Liftable[T] = new Liftable[T] { - def toExpr(x: T) = - val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]] - val tags = summonAll[Tuple.Map[m.MirroredElemTypes, ClassTag]] - tags.zip(liftables).flatMap { case (t: ClassTag[a], l: Liftable[?]) => - t.unapply(x).map(xa => l.asInstanceOf[Liftable[a]].toExpr(xa)) } - .head.asInstanceOf[Expr[T]] -}