Skip to content

Commit ffb832d

Browse files
Liftable derivation moved to the compiler
1 parent 57cdace commit ffb832d

File tree

3 files changed

+37
-32
lines changed

3 files changed

+37
-32
lines changed

library/src-bootstrapped/scala/quoted/Liftable.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scala.quoted
22

33
import scala.reflect.ClassTag
4+
import scala.deriving._
45

56
/** A typeclass for types that can be turned to `quoted.Expr[T]`
67
* without going through an explicit `'{...}` operation.
@@ -305,4 +306,27 @@ object Liftable {
305306
'{ BigDecimal(${Expr(x.toString)}) }
306307
}
307308

309+
inline given productLiftable[T <: Product: Type](given
310+
m : Mirror.ProductOf[T],
311+
em: Expr[Mirror.ProductOf[T]]): Liftable[T] = new Liftable[T] {
312+
def toExpr(x: T) =
313+
val genRepr = Tuple.fromProductTyped(x)
314+
val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]]
315+
val elemsWithLiftables = liftables.zip(genRepr.asInstanceOf[Product].productIterator.toList)
316+
val tupleOfExprs = elemsWithLiftables.map {
317+
case (l: Liftable[a], x) => l.toExpr(x.asInstanceOf[a])
318+
}
319+
val exprOfTuple = Expr.ofTuple(tupleOfExprs)
320+
'{$em.fromProduct($exprOfTuple.asInstanceOf[Product])}
321+
}
322+
323+
inline given sumLiftable[T: Type](given m: Mirror.SumOf[T]): Liftable[T] = new Liftable[T] {
324+
def toExpr(x: T) =
325+
val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]]
326+
val tags = summonAll[Tuple.Map[m.MirroredElemTypes, ClassTag]]
327+
tags.zip(liftables).flatMap { case (t: ClassTag[a], l: Liftable[?]) =>
328+
t.unapply(x).map(xa => l.asInstanceOf[Liftable[a]].toExpr(xa)) }
329+
.head.asInstanceOf[Expr[T]]
330+
}
331+
308332
}

library/src/dotty/DottyPredef.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dotty
22

33
object DottyPredef {
4-
import compiletime.summonFrom
4+
import compiletime.{ summonFrom, erasedValue }
55

66
@forceInline final def assert(assertion: => Boolean, message: => Any): Unit = {
77
if (!assertion)
@@ -38,4 +38,10 @@ object DottyPredef {
3838
}
3939

4040
inline def summon[T](given x: T): x.type = x
41+
42+
inline def summonInline[T] = summonFrom { case x: T => x }
43+
44+
inline def summonAll[T <: Tuple]: List[?] = inline erasedValue[T] match
45+
case _: Unit => Nil
46+
case _: (t *: ts) => summonInline[t] :: summonAll[ts]
4147
}

tests/pos-macros/liftable-derivation/Macro_1.scala

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ import scala.compiletime.{ erasedValue, summonFrom }
99

1010
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)}
1111
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] =
12-
val x: A = Foo(1, "foo")
12+
val x = Foo(1, "foo")
1313
val y: Stuff = Stuff.FooS(10)
14-
Expr(y)
14+
val z: A = x
15+
val e1 = Expr(x)
16+
val e2 = Expr(y)
17+
val e3 = Expr(z)
18+
'{List($e1, $e2, $e3)}
1519

1620
sealed trait A
1721
case class Foo(x: Int, y: String) extends A
@@ -21,32 +25,3 @@ enum Stuff {
2125
case FooS(x: Int)
2226
case BarS(y: String)
2327
}
24-
25-
inline def summonInline[T] = summonFrom { case x: T => x }
26-
27-
inline def summonAll[T <: Tuple]: List[?] = inline erasedValue[T] match
28-
case _: Unit => Nil
29-
case _: (t *: ts) => summonInline[t] :: summonAll[ts]
30-
31-
inline given productLiftable[T <: Product: Type](given
32-
m : Mirror.ProductOf[T],
33-
em: Expr[Mirror.ProductOf[T]]): Liftable[T] = new Liftable[T] {
34-
def toExpr(x: T) =
35-
val genRepr = Tuple.fromProductTyped(x)
36-
val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]]
37-
val elemsWithLiftables = liftables.zip(genRepr.asInstanceOf[Product].productIterator.toList)
38-
val tupleOfExprs = elemsWithLiftables.map {
39-
case (l: Liftable[a], x) => l.toExpr(x.asInstanceOf[a])
40-
}
41-
val exprOfTuple = Expr.ofTuple(tupleOfExprs)
42-
'{$em.fromProduct($exprOfTuple.asInstanceOf[Product])}
43-
}
44-
45-
inline given sumLiftable[T: Type](given m: Mirror.SumOf[T]): Liftable[T] = new Liftable[T] {
46-
def toExpr(x: T) =
47-
val liftables = summonAll[Tuple.Map[m.MirroredElemTypes, Liftable]]
48-
val tags = summonAll[Tuple.Map[m.MirroredElemTypes, ClassTag]]
49-
tags.zip(liftables).flatMap { case (t: ClassTag[a], l: Liftable[?]) =>
50-
t.unapply(x).map(xa => l.asInstanceOf[Liftable[a]].toExpr(xa)) }
51-
.head.asInstanceOf[Expr[T]]
52-
}

0 commit comments

Comments
 (0)