-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
TreeOps.scala
199 lines (161 loc) · 7.39 KB
/
TreeOps.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc.tasty.bridge
import scala.tools.nsc.tasty.{TastyUniverse, TastyModes}, TastyModes._
import scala.tools.tasty.TastyName
import scala.reflect.internal.Flags
/**This layer adds factories that construct typed `scala.reflect` Trees in the shapes that TASTy expects
*/
trait TreeOps { self: TastyUniverse =>
import self.{symbolTable => u}
object untpd {
final val EmptyTree: Tree = u.EmptyTree
}
private class TastyIdent(val tname: TastyName) extends u.Ident(encodeTastyName(tname))
implicit class TreeDecorator(val tree: Tree) {
def typeIdent: TastyName.TypeName = tree match {
case tree: TastyIdent => tree.tname.toTypeName
case _ => TastyName.EmptyTpe
}
}
def showTree(tree: Tree): String = {
// here we want to avoid forcing the symbols of type trees,
// so instead substitute the type tree with an Identifier
// of the `showType`, which does not force.
val tree1 = tree.transform(new u.Transformer {
override def transform(tree: Tree) = tree match {
case tree: u.TypeTree => u.Ident(s"${showType(tree.tpe, wrap = false)}") // ident prints its name directly
case tree => super.transform(tree)
}
})
u.show(tree1)
}
object tpd {
@inline final def Constant(value: Any): Constant =
u.Constant(value)
@inline final def Ident(name: TastyName)(tpe: Type): Tree =
new TastyIdent(name).setType(tpe)
@inline final def Select(qual: Tree, name: TastyName)(implicit ctx: Context): Tree =
selectImpl(qual, name)(implicit ctx => lookupTypeFrom(qual.tpe)(qual.tpe, name))
@inline final def Select(owner: Type)(qual: Tree, name: TastyName)(implicit ctx: Context): Tree =
selectImpl(qual, name)(implicit ctx => lookupTypeFrom(owner)(qual.tpe, name))
private def selectImpl(qual: Tree, name: TastyName)(lookup: Context => Type)(implicit ctx: Context): Tree = {
def selectName(qual: Tree, name: TastyName)(lookup: Context => Type) =
u.Select(qual, encodeTastyName(name)).setType(lookup(ctx))
def selectCtor(qual: Tree) =
u.Select(qual, u.nme.CONSTRUCTOR).setType(qual.tpe.typeSymbol.primaryConstructor.tpe)
if (ctx.mode.is(ReadAnnotationCtor) && name.isSignedConstructor)
selectCtor(qual)
else
selectName(qual, name)(lookup)
}
@inline final def This(qual: TastyName.TypeName)(tpe: Type): Tree =
u.This(encodeTypeName(qual)).setType(tpe)
@inline final def New(tpt: Tree): Tree =
u.New(tpt).setType(safeClassType(tpt.tpe))
@inline final def SingletonTypeTree(ref: Tree): Tree =
u.SingletonTypeTree(ref).setType(ref.tpe)
@inline final def ByNameTypeTree(arg: Tree): Tree =
u.gen.mkFunctionTypeTree(Nil, arg).setType(u.definitions.byNameType(arg.tpe))
@inline final def NamedArg(name: TastyName, value: Tree): Tree =
u.NamedArg(u.Ident(encodeTastyName(name)), value).setType(value.tpe)
def Super(qual: Tree, mixId: TastyName.TypeName)(mixTpe: Type): Tree = {
val owntype = (
if (!mixId.isEmpty) mixTpe
else u.intersectionType(qual.tpe.parents)
)
u.Super(qual, encodeTypeName(mixId)).setType(u.SuperType(qual.tpe, owntype))
}
def PathTree(tpe: Type): Tree = tpe match {
case _:u.TypeRef | _:u.SingleType => u.TypeTree(tpe)
case path: u.ThisType => u.This(path.sym.name.toTypeName).setType(path)
case path: u.ConstantType => u.Literal(path.value).setType(tpe)
case x => throw new MatchError(x)
}
@inline final def TypeTree(tp: Type): Tree = u.TypeTree(tp)
@inline final def LambdaTypeTree(tparams: List[Symbol], body: Tree): Tree =
u.TypeTree(defn.LambdaFromParams(tparams, body.tpe))
def Macro(impl: Tree): Tree = impl match {
case tree @ u.TypeApply(qual, args) =>
u.TypeApply(Macro(qual), args).setType(tree.tpe)
case tree @ u.Select(pre, sel) =>
val sym = if (sel.isTermName) tree.tpe.termSymbol else tree.tpe.typeSymbol
u.Select(Macro(pre), sym).setType(tree.tpe)
case tree: u.TypeTree if tree.tpe.prefix !== u.NoType =>
val sym = tree.tpe match {
case u.SingleType(_, sym) => sym
case u.TypeRef(_, sym, _) => sym
case u.ThisType(sym) => sym
case x => throw new MatchError(x)
}
if (tree.tpe.prefix === u.NoPrefix && (sym.hasFlag(Flags.PACKAGE) && !sym.isPackageObjectOrClass || sym.isLocalToBlock)) {
if (sym.isLocalToBlock) u.Ident(sym).setType(tree.tpe)
else u.This(sym).setType(tree.tpe)
}
else {
u.Select(Macro(u.TypeTree(tree.tpe.prefix)), sym).setType(tree.tpe)
}
case tree =>
tree
}
@inline final def Typed(expr: Tree, tpt: Tree): Tree = u.Typed(expr, tpt).setType(tpt.tpe)
@inline final def Apply(fun: Tree, args: List[Tree]): Tree = u.Apply(fun, args).setType(fnResult(fun.tpe))
def TypeApply(fun: Tree, args: List[Tree]): Tree = {
if (u.definitions.isPredefMemberNamed(fun.tpe.termSymbol, u.TermName("classOf"))) {
assert(args.length == 1 && !fun.tpe.termSymbol.isOverloaded)
u.Literal(Constant(args.head.tpe))
}
else {
u.TypeApply(fun, args).setType(tyconResult(fun.tpe, args.map(_.tpe)))
}
}
def If(cond: Tree, thenp: Tree, elsep: Tree): Tree =
u.If(cond, thenp, elsep).setType(
if (elsep === u.EmptyTree) u.definitions.UnitTpe
else u.lub(thenp.tpe :: elsep.tpe :: Nil)
)
@inline final def SeqLiteral(trees: List[Tree], tpt: Tree): Tree = u.ArrayValue(tpt, trees).setType(tpt.tpe)
def AppliedTypeTree(tpt: Tree, args: List[Tree])(implicit ctx: Context): Tree = {
if (tpt.tpe === AndTpe) {
u.CompoundTypeTree(u.Template(args, u.noSelfType, Nil)).setType(u.intersectionType(args.map(_.tpe)))
} else {
u.AppliedTypeTree(tpt, args).setType(defn.AppliedType(tpt.tpe, args.map(_.tpe)))
}
}
def Annotated(tpt: Tree, annot: Tree)(implicit ctx: Context): Tree = {
if (annot.tpe.typeSymbol === defn.RepeatedAnnot
&& tpt.tpe.typeSymbol.isSubClass(u.definitions.SeqClass)
&& tpt.tpe.typeArgs.length == 1) {
tpd.TypeTree(u.definitions.scalaRepeatedType(tpt.tpe.typeArgs.head))
}
else {
u.Annotated(annot, tpt).setType(defn.AnnotatedType(tpt.tpe, annot))
}
}
def RefinedTypeTree(parent: Tree, decls: List[Tree], refinedCls: Symbol)(implicit ctx: Context): Tree = {
refinedCls.info.parents.head match {
case defn.PolyFunctionType() =>
val polyType = refinedCls.info.decls.map(_.tpe).headOption.fold(defn.NoType)(x => x)
polyFuncIsUnsupported(polyType)
case _ =>
u.CompoundTypeTree(u.Template(parent :: Nil, u.noSelfType, decls)).setType(refinedCls.info)
}
}
def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree): Tree = {
val tpe = alias match {
case untpd.EmptyTree => u.TypeBounds(lo.tpe, hi.tpe)
case alias => new OpaqueTypeBounds(lo.tpe, hi.tpe, alias.tpe)
}
u.TypeBoundsTree(lo, hi).setType(tpe)
}
}
}