Skip to content

Commit f19a184

Browse files
committed
Add quoted Liftable derivation
1 parent b50372e commit f19a184

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import scala.compiletime.{erasedValue, summonFrom}
2+
import scala.deriving._
3+
import scala.quoted._
4+
5+
trait Lft[T]:
6+
def toExpr(x: T): Quotes ?=> Expr[T]
7+
8+
object Lft {
9+
given Lft[Int] with
10+
def toExpr(x: Int) = Expr(x)
11+
12+
inline given derived[T](using inline m: Mirror.Of[T]): Lft[T] = ${ derivedExpr('m) }
13+
14+
private def derivedExpr[T](mirrorExpr: Expr[Mirror.Of[T]])(using qctx: Quotes, tpe: Type[T]): Expr[Lft[T]] = {
15+
mirrorExpr match {
16+
case '{ $mirrorExpr : Mirror.Sum { type MirroredElemTypes = mirroredElemTypes } } =>
17+
val liftableExprs = elemTypesLfts[mirroredElemTypes]
18+
'{
19+
new Lft[T]:
20+
def toExpr(x: T) =
21+
val mirror = $mirrorExpr
22+
val liftable = ${Expr.ofSeq(liftableExprs)}.apply(mirror.ordinal(x)).asInstanceOf[Lft[T]] // TODO generate switch
23+
liftable.toExpr(x)
24+
}
25+
26+
case '{ $mirrorExpr : Mirror.Product { type MirroredElemTypes = mirroredElemTypes } } =>
27+
val liftableExprs = Expr.ofList(elemTypesLfts[mirroredElemTypes])
28+
'{
29+
new Lft[T]:
30+
def toExpr(x: T) =
31+
val liftables = $liftableExprs
32+
val lifted = Expr.ofSeq(liftables.zipWithIndex.map { (liftable, i) =>
33+
liftable.asInstanceOf[Lft[AnyRef]].toExpr(???) // (productElement(x, i))
34+
})
35+
val liftedProduct = '{ Tuple.fromArray(Array($lifted: _*)) }
36+
val mirror = Expr.summon(using '[Mirror.ProductOf[T]]).get
37+
'{ $mirror.fromProduct($liftedProduct) }
38+
}
39+
}
40+
}
41+
42+
private def elemTypesLfts[X: Type](using Quotes): List[Expr[Lft[_]]] =
43+
Type.of[X] match
44+
case '[ head *: tail ] =>
45+
Expr.summon(using '[Lft[head]]).getOrElse(quotes.reflect.report.throwError(s"Could not find given Lft[${Type.show[head]}]")) :: elemTypesLfts[tail]
46+
case '[ Unit ] => Nil
47+
48+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
sealed trait Opt[+T] derives Lft
3+
case class Sm[T](t: T) extends Opt[T] derives Lft
4+
case object Nn extends Opt[Nothing] derives Lft
5+
6+
object Lib {
7+
8+
import scala.quoted._
9+
import Opt.{given _}
10+
11+
inline def smTwo = ${smTwoExpr}
12+
inline def none = ${noneExpr}
13+
14+
private def smTwoExpr(using Quotes): Expr[Opt[Int]] =
15+
summon[Lft[Sm[Int]]].toExpr(Sm(2))
16+
17+
private def noneExpr(using Quotes): Expr[Opt[Int]] =
18+
summon[Lft[Nn.type]].toExpr(Nn)
19+
}
20+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test extends App {
2+
import Opt._
3+
assert(Lib.smTwo == Sm(2))
4+
assert(Lib.none == Nn)
5+
}

0 commit comments

Comments
 (0)