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
|
package scala.reflect.makro
import scala.reflect.api.Universe
/** This package is required by the compiler and <b>should not be used in client code</b>. */
package object internal {
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeClassTag[T](u: Universe): ClassTag[T] = macro materializeClassTag_impl[T]
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeClassTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ClassTag[T]] =
c.Expr[Nothing](c.materializeClassTag(u.tree, implicitly[c.TypeTag[T]].tpe))(c.TypeTag.Nothing)
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeTypeTag[T](u: Universe): u.TypeTag[T] = macro materializeTypeTag_impl[T]
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.TypeTag[T]] =
c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = false))(c.TypeTag.Nothing)
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeConcreteTypeTag[T](u: Universe): u.ConcreteTypeTag[T] = macro materializeConcreteTypeTag_impl[T]
/** This method is required by the compiler and <b>should not be used in client code</b>. */
def materializeConcreteTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.ConcreteTypeTag[T]] =
c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = true))(c.TypeTag.Nothing)
/** This method is required by the compiler and <b>should not be used in client code</b>. */
private[scala] implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils
}
package internal {
private[scala] abstract class Utils {
val c: Context
import c.mirror._
import definitions._
val coreTags = Map(
ByteClass.asType -> newTermName("Byte"),
ShortClass.asType -> newTermName("Short"),
CharClass.asType -> newTermName("Char"),
IntClass.asType -> newTermName("Int"),
LongClass.asType -> newTermName("Long"),
FloatClass.asType -> newTermName("Float"),
DoubleClass.asType -> newTermName("Double"),
BooleanClass.asType -> newTermName("Boolean"),
UnitClass.asType -> newTermName("Unit"),
AnyClass.asType -> newTermName("Any"),
ObjectClass.asType -> newTermName("Object"),
AnyValClass.asType -> newTermName("AnyVal"),
AnyRefClass.asType -> newTermName("AnyRef"),
NothingClass.asType -> newTermName("Nothing"),
NullClass.asType -> newTermName("Null"))
def materializeClassTag(prefix: Tree, tpe: Type): Tree = {
val typetagInScope = c.inferImplicitValue(appliedType(typeRef(prefix.tpe, ConcreteTypeTagClass, Nil), List(tpe)))
def typetagIsSynthetic(tree: Tree) = tree.isInstanceOf[Block] || (tree exists (sub => sub.symbol == TypeTagModule || sub.symbol == ConcreteTypeTagModule))
typetagInScope match {
case success if !success.isEmpty && !typetagIsSynthetic(success) =>
val factory = TypeApply(Select(Ident(ClassTagModule), newTermName("apply")), List(TypeTree(tpe)))
Apply(factory, List(Select(typetagInScope, newTermName("tpe"))))
case _ =>
val result =
tpe match {
case coreTpe if coreTags contains coreTpe =>
Select(Ident(ClassTagModule), coreTags(coreTpe))
case _ =>
if (tpe.typeSymbol == ArrayClass) {
val componentTpe = tpe.typeArguments(0)
val classtagInScope = c.inferImplicitValue(appliedType(typeRef(NoPrefix, ClassTagClass, Nil), List(componentTpe)))
val componentTag = classtagInScope orElse materializeClassTag(prefix, componentTpe)
Select(componentTag, newTermName("wrap"))
} else {
// [Eugene] what's the intended behavior? there's no spec on ClassManifests
// for example, should we ban Array[T] or should we tag them with Array[AnyRef]?
// if its the latter, what should be the result of tagging Array[T] where T <: Int?
if (tpe.typeSymbol.isAbstractType) fail("tpe is an abstract type")
val erasure =
if (tpe.typeSymbol.isDerivedValueClass) tpe // [Eugene to Martin] is this correct?
else tpe.erasure.normalize // necessary to deal with erasures of HK types
val factory = TypeApply(Select(Ident(ClassTagModule), newTermName("apply")), List(TypeTree(tpe)))
Apply(factory, List(TypeApply(Ident(newTermName("classOf")), List(TypeTree(erasure)))))
}
}
try c.typeCheck(result)
catch { case terr @ c.TypeError(pos, msg) => fail(terr) }
}
}
def materializeTypeTag(prefix: Tree, tpe: Type, requireConcreteTypeTag: Boolean): Tree = {
val tagModule = if (requireConcreteTypeTag) ConcreteTypeTagModule else TypeTagModule
val result =
tpe match {
case coreTpe if coreTags contains coreTpe =>
Select(Select(prefix, tagModule.name), coreTags(coreTpe))
case _ =>
try c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, requireConcreteTypeTag = requireConcreteTypeTag)
catch {
case ex: Throwable =>
// [Eugene] cannot pattern match on an abstract type, so had to do this
val ex1 = ex
if (ex.getClass.toString.endsWith("$ReificationError")) {
ex match {
case c.ReificationError(pos, msg) =>
c.error(pos, msg)
EmptyTree
}
} else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) {
ex match {
case c.UnexpectedReificationError(pos, err, cause) =>
if (cause != null) throw cause else throw ex
}
} else {
throw ex
}
}
}
try c.typeCheck(result)
catch { case terr @ c.TypeError(pos, msg) => fail(terr) }
}
private def fail(reason: Any): Nothing = {
val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication
val tpe = tpeTree.tpe
val PolyType(_, MethodType(_, tagTpe)) = fun.tpe
val tagModule = tagTpe.typeSymbol.companionSymbol
if (c.compilerSettings.contains("-Xlog-implicits"))
c.echo(c.enclosingPosition, "cannot materialize " + tagModule.name + "[" + tpe + "] because:\n" + reason)
c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe))
}
}
}
|