summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-06 02:05:10 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:23:11 +0200
commit1708a7fffdb653a638927c2b4ff30a7a0be0f3fe (patch)
tree1d270cc0b3c4a7424f2444a4d1dca460699abb6a /src/library
parentfb67a1d3aea159fd39e5c0fad14ffa089a5d6ba5 (diff)
downloadscala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.gz
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.bz2
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.zip
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].
Diffstat (limited to 'src/library')
-rwxr-xr-xsrc/library/scala/reflect/api/Universe.scala14
-rw-r--r--src/library/scala/reflect/makro/Context.scala15
-rw-r--r--src/library/scala/reflect/makro/internal/Utils.scala148
-rw-r--r--src/library/scala/reflect/makro/internal/macroImpl.scala17
-rw-r--r--src/library/scala/reflect/makro/internal/package.scala17
5 files changed, 38 insertions, 173 deletions
diff --git a/src/library/scala/reflect/api/Universe.scala b/src/library/scala/reflect/api/Universe.scala
index 05b5963c73..ce1b806812 100755
--- a/src/library/scala/reflect/api/Universe.scala
+++ b/src/library/scala/reflect/api/Universe.scala
@@ -33,7 +33,7 @@ abstract class Universe extends Symbols
* }}}
*
* The reifier transforms it to the following expression:
- *
+ *
* {{{
* <[
* val $mr: scala.reflect.api.Universe = <reference to the Universe that calls the reify>
@@ -66,12 +66,6 @@ abstract class Universe extends Symbols
* * Since reified trees can be compiled outside of the scope they've been created in,
* special measures are taken to ensure that all members accessed in the reifee remain visible
*/
- def reify[T](expr: T): Expr[T] = macro Universe.reify[T]
-}
-
-object Universe {
- def reify[T](cc: scala.reflect.makro.Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = {
- import scala.reflect.makro.internal._
- cc.Expr(cc.materializeExpr(cc.prefix.tree, expr.tree))
- }
-}
+ // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ def reify[T](expr: T): Expr[T] = macro ???
+} \ No newline at end of file
diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala
index b8fb0dcce5..b0e15fd572 100644
--- a/src/library/scala/reflect/makro/Context.scala
+++ b/src/library/scala/reflect/makro/Context.scala
@@ -28,17 +28,6 @@ trait Context extends Aliases
val prefix: Expr[PrefixType]
/** Alias to the underlying mirror's reify */
- def reify[T](expr: T): Expr[T] = macro Context.reify[T]
-}
-
-object Context {
- def reify[T](cc: Context{ type PrefixType = Context })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = {
- import cc.mirror._
- import scala.reflect.makro.internal._
- // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure?
- val prefix: Tree = Select(cc.prefix.tree, newTermName("mirror"))
- val prefixTpe = cc.typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe
- prefix setType prefixTpe
- cc.Expr(cc.materializeExpr(prefix, expr.tree))
- }
+ // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ def reify[T](expr: T): Expr[T] = macro ???
}
diff --git a/src/library/scala/reflect/makro/internal/Utils.scala b/src/library/scala/reflect/makro/internal/Utils.scala
deleted file mode 100644
index 3032d8e05d..0000000000
--- a/src/library/scala/reflect/makro/internal/Utils.scala
+++ /dev/null
@@ -1,148 +0,0 @@
-package scala.reflect.makro
-
-import scala.reflect.api.Universe
-import language.implicitConversions
-import language.experimental.macros
-
-/** 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 materializeArrayTag[T](u: Universe): ArrayTag[T] = macro materializeArrayTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeArrayTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ArrayTag[T]] =
- c.Expr[Nothing](c.materializeArrayTag(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 materializeErasureTag[T](u: Universe): ErasureTag[T] = macro materializeErasureTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeErasureTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ErasureTag[T]] =
- c.Expr[Nothing](c.materializeErasureTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing)
-
- /** 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, concrete = 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, concrete = 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"),
- 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")
- }
- }
-}
diff --git a/src/library/scala/reflect/makro/internal/macroImpl.scala b/src/library/scala/reflect/makro/internal/macroImpl.scala
index 9cf4d23072..0dfa8d1654 100644
--- a/src/library/scala/reflect/makro/internal/macroImpl.scala
+++ b/src/library/scala/reflect/makro/internal/macroImpl.scala
@@ -1,5 +1,18 @@
package scala.reflect.makro
package internal
-/** This type is required by the compiler and <b>should not be used in client code</b>. */
-class macroImpl(val referenceToMacroImpl: Any) extends annotation.StaticAnnotation
+/** Links macro definitions with their implementation.
+ * This is necessary to preserve macro def -> macro impl links between compilation runs.
+ *
+ * More precisely, after typechecking right-hand side of a macro def
+ * `typedMacroBody` slaps `macroImpl` annotation onto the macro def
+ * with the result of typechecking as a sole parameter.
+ *
+ * As an unfortunate consequence, this annotation must be defined in scala-library.jar,
+ * because anyone (even those programmers who compile their programs with only scala-library on classpath)
+ * must be able to define macros.
+ *
+ * To lessen the weirdness we define this annotation as `private[scala]`.
+ * It will not prevent pickling, but it will prevent application developers (and scaladocs) from seeing the annotation.
+ */
+private[scala] class macroImpl(val referenceToMacroImpl: Any) extends annotation.StaticAnnotation
diff --git a/src/library/scala/reflect/makro/internal/package.scala b/src/library/scala/reflect/makro/internal/package.scala
new file mode 100644
index 0000000000..4c4acec096
--- /dev/null
+++ b/src/library/scala/reflect/makro/internal/package.scala
@@ -0,0 +1,17 @@
+package scala.reflect.makro
+
+import language.experimental.macros
+import scala.reflect.api.{Universe => ApiUniverse}
+
+// anchors for materialization macros emitted during tag materialization in Implicits.scala
+// implementation is magically hardwired into `scala.reflect.reify.Taggers`
+//
+// todo. once we have implicit macros for tag generation, we can remove these anchors
+// [Eugene++] how do I hide this from scaladoc?
+package object internal {
+ private[scala] def materializeArrayTag[T](u: ApiUniverse): ArrayTag[T] = macro ???
+ private[scala] def materializeErasureTag[T](u: ApiUniverse): ErasureTag[T] = macro ???
+ private[scala] def materializeClassTag[T](u: ApiUniverse): ClassTag[T] = macro ???
+ private[scala] def materializeTypeTag[T](u: ApiUniverse): u.TypeTag[T] = macro ???
+ private[scala] def materializeConcreteTypeTag[T](u: ApiUniverse): u.ConcreteTypeTag[T] = macro ???
+}