Skip to content

Commit 597d4ca

Browse files
committed
Add regression that demonstrates a type class derived method with macros
1 parent 315071c commit 597d4ca

File tree

5 files changed

+81
-19
lines changed

5 files changed

+81
-19
lines changed

tests/run-macros/i8007.check

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
List("name", "age")
1+
List("name", "age")
2+
3+
Test 23

tests/run-macros/i8007/Macro_1.scala

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.quoted._
33
import scala.quoted.matching._
44
import scala.compiletime.{erasedValue, summonFrom, constValue}
55

6-
object Macro {
6+
object Macro1 {
77
case class Person(name: String, age: Int)
88

99
def mirrorFields[T](t: Type[T])(given qctx: QuoteContext): List[String] =
@@ -12,23 +12,21 @@ object Macro {
1212
case '[Unit] => Nil
1313
}
1414

15-
inline def usingSummonFrom[T](value: =>T): List[String] =
16-
${ usingSummonFromImpl('value) }
15+
// Macro method 1
16+
// Demonstrates the use of quoted pattern matching
17+
// over a refined type, extracting the tuple type
18+
// for e.g., MirroredElemLabels
19+
inline def test1[T](value: =>T): List[String] =
20+
${ test1Impl('value) }
1721

18-
def usingSummonFromImpl[T: Type](value: Expr[T])(given qctx: QuoteContext): Expr[List[String]] = {
22+
def test1Impl[T: Type](value: Expr[T])(given qctx: QuoteContext): Expr[List[String]] = {
1923
import qctx.tasty.{_, given}
2024

21-
2225
val mirrorTpe = '[Mirror.Of[T]]
2326

2427
summonExpr(given mirrorTpe).get match {
25-
case '{ $m: Mirror.ProductOf[T] } => {
26-
val typeMember = TypeSelect(m.unseal, "MirroredElemLabels")
27-
28-
type TT
29-
implicit val TT: quoted.Type[TT] = typeMember.tpe.seal.asInstanceOf[quoted.Type[TT]]
30-
31-
Expr(mirrorFields('[TT]))
28+
case '{ $m: Mirror.ProductOf[T]{ type MirroredElemLabels = $t } } => {
29+
Expr(mirrorFields(t))
3230
}
3331
}
3432
}

tests/run-macros/i8007/Macro_2.scala

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import scala.deriving._
2+
import scala.quoted._
3+
import scala.quoted.matching._
4+
import scala.compiletime.{erasedValue, summonFrom, constValue}
5+
6+
object Macro2 {
7+
8+
def mirrorFields[T](t: Type[T])(given qctx: QuoteContext): List[String] =
9+
t match {
10+
case '[$field *: $fields] => field.show.substring(1, field.show.length-1) :: mirrorFields(fields)
11+
case '[Unit] => Nil
12+
}
13+
14+
trait JsonEncoder[T] {
15+
def encode(elem: T): String
16+
}
17+
18+
object JsonEncoder {
19+
def emitJsonEncoder[T](body: T => String): JsonEncoder[T]=
20+
new JsonEncoder[T] {
21+
def encode(elem: T): String = body(elem)
22+
}
23+
24+
def derived[T: Type](ev: Expr[Mirror.Of[T]])(given qctx: QuoteContext): Expr[JsonEncoder[T]] = {
25+
import qctx.tasty.{_, given}
26+
27+
val fields = ev match {
28+
case '{ $m: Mirror.ProductOf[T] { type MirroredElemLabels = $t } } =>
29+
mirrorFields(t)
30+
}
31+
32+
val body: Expr[T] => Expr[String] = elem =>
33+
fields.reverse.foldLeft(Expr("")){ (acc, field) =>
34+
val res = Select.unique(elem.unseal, field).seal
35+
'{ $res.toString + " " + $acc }
36+
}
37+
38+
'{
39+
emitJsonEncoder((x: T) => ${body('x)})
40+
}
41+
}
42+
}
43+
44+
inline def test2[T](value: =>T): Unit = ${ test2Impl('value) }
45+
46+
def test2Impl[T: Type](value: Expr[T])(given qctx: QuoteContext): Expr[Unit] = {
47+
import qctx.tasty.{_, given}
48+
49+
val mirrorTpe = '[Mirror.Of[T]]
50+
val mirrorExpr = summonExpr(given mirrorTpe).get
51+
val derivedInstance = JsonEncoder.derived(mirrorExpr)
52+
53+
'{
54+
val res = $derivedInstance.encode($value)
55+
println(res)
56+
}
57+
}
58+
}

tests/run-macros/i8007/Test_2.scala

Lines changed: 0 additions & 6 deletions
This file was deleted.

tests/run-macros/i8007/Test_3.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Macro1._
2+
import Macro2._
3+
4+
@main def Test() = {
5+
val list = test1(Person("Test", 23))
6+
println(list)
7+
println
8+
9+
test2(Person("Test", 23))
10+
}

0 commit comments

Comments
 (0)