Skip to content
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")
}
}

0 comments on commit 1708a7f

Please sign in to comment.
You can’t perform that action at this time.