From 1708a7fffdb653a638927c2b4ff30a7a0be0f3fe Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 6 Jun 2012 02:05:10 +0200 Subject: 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]. --- src/library/scala/reflect/api/Universe.scala | 14 +- src/library/scala/reflect/makro/Context.scala | 15 +-- .../scala/reflect/makro/internal/Utils.scala | 148 --------------------- .../scala/reflect/makro/internal/macroImpl.scala | 17 ++- .../scala/reflect/makro/internal/package.scala | 17 +++ 5 files changed, 38 insertions(+), 173 deletions(-) delete mode 100644 src/library/scala/reflect/makro/internal/Utils.scala create mode 100644 src/library/scala/reflect/makro/internal/package.scala (limited to 'src/library') 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 = @@ -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 should not be used in client code. */ -package object internal { - /** This method is required by the compiler and should not be used in client code. */ - def materializeArrayTag[T](u: Universe): ArrayTag[T] = macro materializeArrayTag_impl[T] - - /** This method is required by the compiler and should not be used in client code. */ - 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 should not be used in client code. */ - def materializeErasureTag[T](u: Universe): ErasureTag[T] = macro materializeErasureTag_impl[T] - - /** This method is required by the compiler and should not be used in client code. */ - 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 should not be used in client code. */ - def materializeClassTag[T](u: Universe): ClassTag[T] = macro materializeClassTag_impl[T] - - /** This method is required by the compiler and should not be used in client code. */ - 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 should not be used in client code. */ - def materializeTypeTag[T](u: Universe): u.TypeTag[T] = macro materializeTypeTag_impl[T] - - /** This method is required by the compiler and should not be used in client code. */ - 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 should not be used in client code. */ - def materializeConcreteTypeTag[T](u: Universe): u.ConcreteTypeTag[T] = macro materializeConcreteTypeTag_impl[T] - - /** This method is required by the compiler and should not be used in client code. */ - 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 should not be used in client code. */ - 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 should not be used in client code. */ -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 ??? +} -- cgit v1.2.3