summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Macros.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-05-28 11:42:33 +0200
committerEugene Burmako <xeno.by@gmail.com>2013-06-02 21:58:37 +0200
commit82f0925b69db8b5f9a3b10f58926c574433ca423 (patch)
tree691ae3351459eed9b289c9eeecbfe1332e9e80a9 /src/compiler/scala/tools/nsc/typechecker/Macros.scala
parentb136b42d43a8d745848e58a4dbba57d866bdc2cc (diff)
downloadscala-82f0925b69db8b5f9a3b10f58926c574433ca423.tar.gz
scala-82f0925b69db8b5f9a3b10f58926c574433ca423.tar.bz2
scala-82f0925b69db8b5f9a3b10f58926c574433ca423.zip
refactors IMPLPARAM_xxx constants into value classes
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Macros.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala76
1 files changed, 53 insertions, 23 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index baef84bc8e..6c4d1e20aa 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -14,6 +14,8 @@ import scala.reflect.macros.runtime.{AbortMacroException, MacroRuntimes}
import scala.reflect.runtime.{universe => ru}
import scala.reflect.macros.compiler.DefaultMacroCompiler
import scala.tools.reflect.FastTrack
+import scala.runtime.ScalaRunTime
+import Fingerprint._
/**
* Code to deal with macros, namely with:
@@ -94,8 +96,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// * c.WeakTypeTag[T] => index of the type parameter corresponding to that type tag
// * everything else (e.g. scala.reflect.macros.Context) => IMPLPARAM_OTHER
// f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: Context)(x: c.Expr[T], y: c.Tree): (U, V) = ???
- // `signature` will be equal to List(List(-1), List(-1, -2), List(0, 2))
- signature: List[List[Int]],
+ // `signature` will be equal to List(List(Other), List(Lifted, Other), List(Tagged(0), Tagged(2)))
+ signature: List[List[Fingerprint]],
// type arguments part of a macro impl ref (the right-hand side of a macro definition)
// these trees don't refer to a macro impl, so we can pickle them as is
targs: List[Tree]) {
@@ -104,10 +106,6 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
def is_??? = className == Predef_???.owner.javaClassName && methName == Predef_???.name.encoded
}
- final val IMPLPARAM_TAG = 0 // actually it's zero and above, this is just a lower bound for >= checks
- final val IMPLPARAM_OTHER = -1
- final val IMPLPARAM_EXPR = -2
-
/** Macro def -> macro impl bindings are serialized into a `macroImpl` annotation
* with synthetic content that carries the payload described in `MacroImplBinding`.
*
@@ -120,28 +118,30 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* @scala.reflect.macros.internal.macroImpl(
* `macro`(
* "isBundle" = false,
- * "signature" = List(-1),
+ * "signature" = List(Other),
* "methodName" = "impl",
* "versionFormat" = <current version format>,
* "className" = "Macros$"))
*/
object MacroImplBinding {
- val versionFormat = 3
+ val versionFormat = 4.0
def pickleAtom(obj: Any): Tree =
obj match {
case list: List[_] => Apply(Ident(ListModule), list map pickleAtom)
case s: String => Literal(Constant(s))
- case i: Int => Literal(Constant(i))
+ case d: Double => Literal(Constant(d))
case b: Boolean => Literal(Constant(b))
+ case f: Fingerprint => Literal(Constant(f.value))
}
def unpickleAtom(tree: Tree): Any =
tree match {
case Apply(list @ Ident(_), args) if list.symbol == ListModule => args map unpickleAtom
case Literal(Constant(s: String)) => s
- case Literal(Constant(i: Int)) => i
+ case Literal(Constant(d: Double)) => d
case Literal(Constant(b: Boolean)) => b
+ case Literal(Constant(i: Int)) => new Fingerprint(i)
}
def pickle(macroImplRef: Tree): Tree = {
@@ -161,15 +161,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
loop(owner)
}
- def signature: List[List[Int]] = {
- def fingerprint(tpe: Type): Int = tpe.dealiasWiden match {
+ def signature: List[List[Fingerprint]] = {
+ def fingerprint(tpe: Type): Fingerprint = tpe.dealiasWiden match {
case TypeRef(_, RepeatedParamClass, underlying :: Nil) => fingerprint(underlying)
- case ExprClassOf(_) => IMPLPARAM_EXPR
- case _ => IMPLPARAM_OTHER
+ case ExprClassOf(_) => Lifted
+ case _ => Other
}
val transformed = transformTypeTagEvidenceParams(macroImplRef, (param, tparam) => tparam)
- mmap(transformed)(p => if (p.isTerm) fingerprint(p.info) else p.paramPos)
+ mmap(transformed)(p => if (p.isTerm) fingerprint(p.info) else Tagged(p.paramPos))
}
val payload = List[(String, Any)](
@@ -214,13 +214,25 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
val Apply(_, pickledPayload) = wrapped
val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap
- val pickleVersionFormat = payload("versionFormat").asInstanceOf[Int]
- if (versionFormat != pickleVersionFormat) throw new Error(s"macro impl binding format mismatch: expected $versionFormat, actual $pickleVersionFormat")
+ def fail(msg: String) = abort(s"bad macro impl binding: $msg")
+ def unpickle[T](field: String, clazz: Class[T]): T = {
+ def failField(msg: String) = fail(s"$field $msg")
+ if (!payload.contains(field)) failField("is supposed to be there")
+ val raw: Any = payload(field)
+ if (raw == null) failField(s"is not supposed to be null")
+ val expected = ScalaRunTime.box(clazz)
+ val actual = raw.getClass
+ if (!expected.isAssignableFrom(actual)) failField(s"has wrong type: expected $expected, actual $actual")
+ raw.asInstanceOf[T]
+ }
+
+ val pickleVersionFormat = unpickle("versionFormat", classOf[Double])
+ if (versionFormat != pickleVersionFormat) fail(s"expected version format $versionFormat, actual $pickleVersionFormat")
- val isBundle = payload("isBundle").asInstanceOf[Boolean]
- val className = payload("className").asInstanceOf[String]
- val methodName = payload("methodName").asInstanceOf[String]
- val signature = payload("signature").asInstanceOf[List[List[Int]]]
+ val isBundle = unpickle("isBundle", classOf[Boolean])
+ val className = unpickle("className", classOf[String])
+ val methodName = unpickle("methodName", classOf[String])
+ val signature = unpickle("signature", classOf[List[List[Fingerprint]]])
MacroImplBinding(isBundle, className, methodName, signature, targs)
}
}
@@ -376,7 +388,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
val wrappedArgs = mapWithIndex(args)((arg, j) => {
val fingerprint = implParams(min(j, implParams.length - 1))
fingerprint match {
- case IMPLPARAM_EXPR => context.Expr[Nothing](arg)(TypeTag.Nothing) // TODO: SI-5752
+ case Lifted => context.Expr[Nothing](arg)(TypeTag.Nothing) // TODO: SI-5752
case _ => abort(s"unexpected fingerprint $fingerprint in $binding with paramss being $paramss " +
s"corresponding to arg $arg in $argss")
}
@@ -406,7 +418,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// then T and U need to be inferred from the lexical scope of the call using `asSeenFrom`
// whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node
// also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
- val tags = signature.flatten filter (_ >= IMPLPARAM_TAG) map (paramPos => {
+ val tags = signature.flatten collect { case f if f.isTag => f.paramPos } map (paramPos => {
val targ = binding.targs(paramPos).tpe.typeSymbol
val tpe = if (targ.isTypeParameterOrSkolem) {
if (targ.owner == macroDef) {
@@ -787,3 +799,21 @@ object MacrosStats {
val macroExpandCount = Statistics.newCounter ("#macro expansions", "typer")
val macroExpandNanos = Statistics.newSubTimer("time spent in macroExpand", typerNanos)
}
+
+class Fingerprint(val value: Int) extends AnyVal {
+ def paramPos = { assert(isTag, this); value }
+ def isTag = value >= 0
+ def isOther = this == Other
+ def isExpr = this == Lifted
+ override def toString = this match {
+ case Other => "Other"
+ case Lifted => "Expr"
+ case _ => s"Tag($value)"
+ }
+}
+
+object Fingerprint {
+ def Tagged(tparamPos: Int) = new Fingerprint(tparamPos)
+ val Other = new Fingerprint(-1)
+ val Lifted = new Fingerprint(-2)
+}