Skip to content

Commit b0f65f6

Browse files
committed
Support GenLens[Employee](_.addr.streetNumber)
1 parent 5e1eb67 commit b0f65f6

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

tests/run-with-compiler/i5941/macro_1.scala

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,48 @@ object Lens {
1717
import util._
1818
import quoted.Toolbox.Default._
1919

20-
// obj.copy(field = value)
21-
def setterBody(obj: Expr[S], value: Expr[T], field: String): Expr[S] =
22-
Term.Select.overloaded(obj.unseal, "copy", Nil, Term.NamedArg(field, value.unseal) :: Nil).seal[S]
20+
21+
// obj.copy(a = obj.a.copy(b = a.b.copy(c = v)))
22+
def setterBody(obj: Term, value: Term, fields: List[String]): Term = {
23+
// o.copy(field = value)
24+
def helper(obj: Term, value: Term, field: String): Term =
25+
Term.Select.overloaded(obj, "copy", Nil, Term.NamedArg(field, value) :: Nil)
26+
27+
fields match {
28+
case field :: Nil => helper(obj, value, field)
29+
case field :: fields =>
30+
helper(obj, setterBody(Term.Select.unique(obj, field), value, fields), field)
31+
}
32+
}
33+
34+
object Path {
35+
private def recur(tree: Term, selects: List[String]): Option[(Term, List[String])] = tree match {
36+
case Term.Ident(_) if selects.nonEmpty => Some((tree, selects))
37+
case Term.Select(qual, name) => recur(qual, name :: selects)
38+
case _ => None
39+
}
40+
41+
def unapply(t: Term): Option[(Term, List[String])] = recur(t, Nil)
42+
}
43+
44+
object Function {
45+
def unapply(t: Term): Option[(List[ValDef], Term)] = t match {
46+
case Term.Inlined(
47+
None, Nil,
48+
Term.Block(
49+
(ddef @ DefDef(_, Nil, params :: Nil, _, Some(body))) :: Nil,
50+
Term.Lambda(meth, _)
51+
)
52+
) if meth.symbol == ddef.symbol => Some((params, body))
53+
case _ => None
54+
}
55+
}
2356

2457
// exception: getter.unseal.underlyingArgument
2558
getter.unseal match {
26-
case Term.Inlined(
27-
None, Nil,
28-
Term.Block(
29-
DefDef(_, Nil, (param :: Nil) :: Nil, _, Some(Term.Select(o, field))) :: Nil,
30-
Term.Lambda(meth, _)
31-
)
32-
) if o.symbol == param.symbol =>
59+
case Function(param :: Nil, Path(o, fields)) if o.symbol == param.symbol =>
3360
'{
34-
val setter = (t: T) => (s: S) => ~setterBody('(s), '(t), field)
61+
val setter = (t: T) => (s: S) => ~setterBody(('(s)).unseal, ('(t)).unseal, fields).seal[S]
3562
apply(~getter)(setter)
3663
}
3764
case _ =>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
case class Address(streetNumber: Int, streetName: String)
22

3+
case class Employee(name: String, addr: Address)
4+
35
object Test {
46
def main(args: Array[String]): Unit = {
57
val len = GenLens[Address](_.streetNumber)
68
val address = Address(10, "High Street")
79
assert(len.get(address) == 10)
810
val addr2 = len.set(5, address)
911
assert(len.get(addr2) == 5)
12+
13+
val len2 = GenLens[Employee](_.addr.streetNumber)
14+
val employee = Employee("Bob", Address(10, "High Street"))
15+
assert(len2.get(employee) == 10)
16+
val employee2 = len2.set(5, employee)
17+
assert(employee2.name == "Bob")
18+
assert(len2.get(employee2) == 5)
1019
}
1120
}

0 commit comments

Comments
 (0)