-
Notifications
You must be signed in to change notification settings - Fork 1k
/
ExprMap.scala
157 lines (138 loc) · 6.86 KB
/
ExprMap.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package scala.quoted
trait ExprMap:
/** Map an expression `e` with a type `T` */
def transform[T](e: Expr[T])(using Type[T])(using Quotes): Expr[T]
/** Map sub-expressions an expression `e` with a type `T` */
def transformChildren[T](e: Expr[T])(using Type[T])(using Quotes): Expr[T] = {
import quotes.reflect._
final class MapChildren() {
def transformStatement(tree: Statement)(owner: Symbol): Statement = {
tree match {
case tree: Term =>
transformTerm(tree, TypeRepr.of[Any])(owner)
case tree: Definition =>
transformDefinition(tree)(owner)
case tree @ (_:Import | _:Export) =>
tree
}
}
def transformDefinition(tree: Definition)(owner: Symbol): Definition = {
tree match {
case tree: ValDef =>
val owner = tree.symbol
val rhs1 = tree.rhs.map(x => transformTerm(x, tree.tpt.tpe)(owner))
ValDef.copy(tree)(tree.name, tree.tpt, rhs1)
case tree: DefDef =>
val owner = tree.symbol
DefDef.copy(tree)(tree.name, tree.paramss, tree.returnTpt, tree.rhs.map(x => transformTerm(x, tree.returnTpt.tpe)(owner)))
case tree: TypeDef =>
tree
case tree: ClassDef =>
val newBody = transformStats(tree.body)(owner)
ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.self, newBody)
}
}
def transformTermChildren(tree: Term, tpe: TypeRepr)(owner: Symbol): Term = tree match {
case Ident(name) =>
tree
case Select(qualifier, name) =>
Select.copy(tree)(transformTerm(qualifier, qualifier.tpe)(owner), name)
case This(qual) =>
tree
case Super(qual, mix) =>
tree
case tree @ Apply(fun, args) =>
val MethodType(_, tpes, _) = fun.tpe.widen: @unchecked
val tpes1 = tpes.map {
case ByNameType(tpe) => tpe
case tpe => tpe
}
Apply.copy(tree)(transformTerm(fun, TypeRepr.of[Any])(owner), transformTerms(args, tpes1)(owner))
case TypeApply(fun, args) =>
TypeApply.copy(tree)(transformTerm(fun, TypeRepr.of[Any])(owner), args)
case _: Literal =>
tree
case New(tpt) =>
New.copy(tree)(transformTypeTree(tpt)(owner))
case Typed(expr, tpt) =>
val tp = tpt.tpe match
case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "<repeated>"), List(tp0: TypeRepr)) =>
TypeRepr.of[Seq].appliedTo(tp0)
case tp => tp
Typed.copy(tree)(transformTerm(expr, tp)(owner), transformTypeTree(tpt)(owner))
case tree: NamedArg =>
NamedArg.copy(tree)(tree.name, transformTerm(tree.value, tpe)(owner))
case Assign(lhs, rhs) =>
Assign.copy(tree)(lhs, transformTerm(rhs, lhs.tpe.widen)(owner))
case Block(stats, expr) =>
Block.copy(tree)(transformStats(stats)(owner), transformTerm(expr, tpe)(owner))
case If(cond, thenp, elsep) =>
If.copy(tree)(
transformTerm(cond, TypeRepr.of[Boolean])(owner),
transformTerm(thenp, tpe)(owner),
transformTerm(elsep, tpe)(owner))
case _: Closure =>
tree
case Match(selector, cases) =>
Match.copy(tree)(transformTerm(selector, selector.tpe)(owner), transformCaseDefs(cases, tpe)(owner))
case Return(expr, from) =>
// FIXME
// ctx.owner seems to be set to the wrong symbol
// Return.copy(tree)(transformTerm(expr, expr.tpe))
tree
case While(cond, body) =>
While.copy(tree)(transformTerm(cond, TypeRepr.of[Boolean])(owner), transformTerm(body, TypeRepr.of[Any])(owner))
case Try(block, cases, finalizer) =>
Try.copy(tree)(transformTerm(block, tpe)(owner), transformCaseDefs(cases, TypeRepr.of[Any])(owner), finalizer.map(x => transformTerm(x, TypeRepr.of[Any])(owner)))
case Repeated(elems, elemtpt) =>
Repeated.copy(tree)(transformTerms(elems, elemtpt.tpe)(owner), elemtpt)
case Inlined(call, bindings, expansion) =>
Inlined.copy(tree)(call, transformDefinitions(bindings)(owner), transformTerm(expansion, tpe)(owner))
}
def transformTerm(tree: Term, tpe: TypeRepr)(owner: Symbol): Term =
tree match
case _: Closure =>
tree
case _: Inlined =>
transformTermChildren(tree, tpe)(owner)
case _ if tree.isExpr =>
// WARNING: Never do a cast like this in user code (acceptable within the stdlib).
// In theory we should use `tree.asExpr match { case '{ $expr: t } => transform(expr).asTerm }`
// This is to avoid conflicts when re-bootstrapping the library.
type X
val expr = tree.asExpr.asInstanceOf[Expr[X]]
val t = tpe.asType.asInstanceOf[Type[X]]
val transformedExpr = transform(expr)(using t)
transformedExpr.asTerm
case _ =>
transformTermChildren(tree, tpe)(owner)
def transformTypeTree(tree: TypeTree)(owner: Symbol): TypeTree = tree
def transformCaseDef(tree: CaseDef, tpe: TypeRepr)(owner: Symbol): CaseDef =
CaseDef.copy(tree)(tree.pattern, tree.guard.map(x => transformTerm(x, TypeRepr.of[Boolean])(owner)), transformTerm(tree.rhs, tpe)(owner))
def transformTypeCaseDef(tree: TypeCaseDef)(owner: Symbol): TypeCaseDef =
TypeCaseDef.copy(tree)(transformTypeTree(tree.pattern)(owner), transformTypeTree(tree.rhs)(owner))
def transformStats(trees: List[Statement])(owner: Symbol): List[Statement] =
trees.mapConserve(x => transformStatement(x)(owner))
def transformDefinitions(trees: List[Definition])(owner: Symbol): List[Definition] =
trees.mapConserve(x => transformDefinition(x)(owner))
def transformTerms(trees: List[Term], tpes: List[TypeRepr])(owner: Symbol): List[Term] =
var tpes2 = tpes // TODO use proper zipConserve
trees.mapConserve{ x =>
val tpe :: tail = tpes2: @unchecked
tpes2 = tail
transformTerm(x, tpe)(owner)
}
def transformTerms(trees: List[Term], tpe: TypeRepr)(owner: Symbol): List[Term] =
trees.mapConserve(x => transformTerm(x, tpe)(owner))
def transformTypeTrees(trees: List[TypeTree])(owner: Symbol): List[TypeTree] =
trees.mapConserve(x => transformTypeTree(x)(owner))
def transformCaseDefs(trees: List[CaseDef], tpe: TypeRepr)(owner: Symbol): List[CaseDef] =
trees.mapConserve(x => transformCaseDef(x, tpe)(owner))
def transformTypeCaseDefs(trees: List[TypeCaseDef])(owner: Symbol): List[TypeCaseDef] =
trees.mapConserve(x => transformTypeCaseDef(x)(owner))
}
new MapChildren()
.transformTermChildren(e.asTerm, TypeRepr.of[T])(Symbol.spliceOwner)
.asExprOf[T]
}
end ExprMap