Permalink
Browse files

macros: refactoring of fast track infrastructure

As a result, hardwired macros don't need implementation stubs.
This is very important, because in a few commits scala.reflect.makro.Context
will move out from scala-library.jar.

Also adding fast track entries doesn't require jumping through hoops
with PDTs. It's as simple as defining PartialFunction[Tree, Any].
  • Loading branch information...
xeno-by committed Jun 6, 2012
1 parent fb67a1d commit 1708a7fffdb653a638927c2b4ff30a7a0be0f3fe
@@ -1 +1 @@
-0939b5f357e4b0a6ecb3b6218a1a53841aae258d ?scala-compiler.jar
+fbdefcf1a7a2bcd71373f08acd13e84d869ceeaf ?scala-compiler.jar
@@ -1 +1 @@
-2abaea76bd10ccb7afe29604b1156fb7f8c6c36e ?scala-library.jar
+e19956225d174f0f3bc0a1d014f208b68d399d66 ?scala-library.jar
@@ -486,6 +486,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
// [Eugene] is this a good place for ReflectMirrorPrefix?
def ReflectMirrorPrefix = gen.mkAttributedRef(ReflectMirror) setType singleType(ReflectMirror.owner.thisPrefix, ReflectMirror)
+ lazy val ApiUniverseClass = requiredClass[scala.reflect.api.Universe]
+ def ApiUniverseReify = getMemberMethod(ApiUniverseClass, nme.reify)
+
lazy val PartialManifestClass = requiredClass[scala.reflect.ClassManifest[_]]
lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifest.type]
lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]]
@@ -130,6 +130,7 @@ trait StdNames {
final val ClassTag: NameType = "ClassTag"
final val TypeTag : NameType = "TypeTag"
final val ConcreteTypeTag: NameType = "ConcreteTypeTag"
+ final val String: NameType = "String"
// fictions we use as both types and terms
final val ERROR: NameType = "<error>"
@@ -223,7 +224,6 @@ trait StdNames {
final val Product: NameType = "Product"
final val Serializable: NameType = "Serializable"
final val Singleton: NameType = "Singleton"
- final val String: NameType = "String"
final val Throwable: NameType = "Throwable"
final val Annotation: NameType = "Annotation"
@@ -0,0 +1,104 @@
+package scala.reflect.reify
+
+import scala.reflect.makro.{ReificationError, UnexpectedReificationError}
+import scala.reflect.makro.runtime.Context
+
+abstract class Taggers {
+ 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"),
+ StringClass.asType -> newTermName("String"))
+
+ // todo. the following two methods won't be necessary once we implement implicit macro generators for tags
+
+ def materializeArrayTag(prefix: Tree, tpe: Type): Tree =
+ materializeClassTag(prefix, tpe)
+
+ def materializeErasureTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree =
+ if (concrete) materializeClassTag(prefix, tpe) else materializeTypeTag(prefix, tpe, concrete = false)
+
+ def materializeClassTag(prefix: Tree, tpe: Type): Tree =
+ materializeTag(prefix, tpe, ClassTagModule, {
+ val erasure = c.reifyErasure(tpe, concrete = true)
+ val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe)))
+ Apply(factory, List(erasure))
+ })
+
+ def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = {
+ val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule
+ materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete))
+ }
+
+ private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = {
+ val result =
+ tpe match {
+ case coreTpe if coreTags contains coreTpe =>
+ val ref = if (tagModule.owner.isPackageClass) Ident(tagModule) else Select(prefix, tagModule.name)
+ Select(ref, coreTags(coreTpe))
+ case _ =>
+ val manifestInScope = nonSyntheticManifestInScope(tpe)
+ if (manifestInScope.isEmpty) translatingReificationErrors(materializer)
+ else gen.mkMethodCall(staticModule("scala.reflect.package"), newTermName("manifestToConcreteTypeTag"), List(tpe), List(manifestInScope))
+ }
+ try c.typeCheck(result)
+ catch { case terr @ c.TypeError(pos, msg) => failTag(result, terr) }
+ }
+
+ private def nonSyntheticManifestInScope(tpe: Type) = {
+ val ManifestClass = staticClass("scala.reflect.Manifest")
+ val ManifestModule = staticModule("scala.reflect.Manifest")
+ val manifest = c.inferImplicitValue(appliedType(ManifestClass.asTypeConstructor, List(tpe)))
+ val notOk = manifest.isEmpty || (manifest exists (sub => sub.symbol != null && (sub.symbol == ManifestModule || sub.symbol.owner == ManifestModule)))
+ if (notOk) EmptyTree else manifest
+ }
+
+ def materializeExpr(prefix: Tree, expr: Tree): Tree = {
+ val result = translatingReificationErrors(c.reifyTree(prefix, expr))
+ try c.typeCheck(result)
+ catch { case terr @ c.TypeError(pos, msg) => failExpr(result, terr) }
+ }
+
+ private def translatingReificationErrors(materializer: => Tree): Tree = {
+ try materializer
+ catch {
+ case ReificationError(pos, msg) =>
+ c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling
+ EmptyTree
+ case UnexpectedReificationError(pos, err, cause) if cause != null =>
+ throw cause
+ }
+ }
+
+ private def failTag(result: Tree, 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, s"cannot materialize ${tagModule.name}[$tpe] as $result because:\n$reason")
+ c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe))
+ }
+
+ private def failExpr(result: Tree, reason: Any): Nothing = {
+ val Apply(_, expr :: Nil) = c.macroApplication
+ c.abort(c.enclosingPosition, s"Cannot materialize $expr as $result because:\n$reason")
+ }
+}
Oops, something went wrong.

0 comments on commit 1708a7f

Please sign in to comment.