Skip to content

Commit

Permalink
moves Expr from api to base
Browse files Browse the repository at this point in the history
This is the first step in supporting serialization for exprs and type tags.

Generally speaking universes and mirrors cannot be serialized (even not taking
into account all the amount of scalac-specific transient stuff, java mirrors
use classloaders, which are not serializable).

Hence we can only serialize tree and type creators, and deserialize them into
the mirror we surely know will be there - the scala.reflect.basis.rootMirror.

To do that we need to have exprs in scala.reflect.base. Luckily all the trees
are already in base, we only need to move a single file to scala-library.jar.
Another good news is that reification logic is simplified, because we don't
have to special case exprs as being defined in ApiUniverseClass.
  • Loading branch information
xeno-by committed Aug 2, 2012
1 parent a0a63c4 commit f7164b8
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 88 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/reify/Reifier.scala
Expand Up @@ -115,7 +115,7 @@ abstract class Reifier extends States
// todo. maybe try `resetLocalAttrs` once the dust settles
var importantSymbols = Set[Symbol](
NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorOfClass,
BaseUniverseClass, ApiUniverseClass, JavaUniverseClass, ReflectRuntimePackage, ReflectRuntimeCurrentMirror)
BaseUniverseClass, JavaUniverseClass, ReflectRuntimePackage, ReflectRuntimeCurrentMirror)
importantSymbols ++= importantSymbols map (_.companionSymbol)
importantSymbols ++= importantSymbols map (_.moduleClass)
importantSymbols ++= importantSymbols map (_.linkedClassOfClass)
Expand Down
28 changes: 3 additions & 25 deletions src/compiler/scala/reflect/reify/utils/Extractors.scala
Expand Up @@ -20,11 +20,6 @@ trait Extractors {
// ()
// };
// def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = {
// val $u: scala.reflect.api.Universe = $m$untyped.universe.asInstanceOf[scala.reflect.api.Universe];
// val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
// applyImpl($m).asInstanceOf[U#Tree];
// }
// def applyImpl[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = {
// val $u: U = $m$untyped.universe;
// val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
// $u.Apply($u.Select($u.Select($u.build.This($m.staticPackage("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2))))
Expand All @@ -51,23 +46,7 @@ trait Extractors {
val tparamu = newTypeName("U")
val (reifierBase, reifierName, reifierTpt, reifierUniverse) = flavor match {
case tpnme.REIFY_TYPECREATOR_PREFIX => (TypeCreatorClass, nme.apply, SelectFromTypeTree(Ident(tparamu), tpnme.Type), BaseUniverseClass)
case tpnme.REIFY_TREECREATOR_PREFIX => (TreeCreatorClass, nme.applyImpl, SelectFromTypeTree(Ident(BaseUniverseClass), tpnme.Tree), ApiUniverseClass)
case _ => throw new Error(s"unexpected flavor $flavor")
}
val reifierPreamble = flavor match {
case tpnme.REIFY_TYPECREATOR_PREFIX => Nil
case tpnme.REIFY_TREECREATOR_PREFIX => List[Tree](
DefDef(NoMods,
nme.apply,
List(TypeDef(Modifiers(PARAM), tparamu, List(), TypeBoundsTree(Ident(NothingClass), CompoundTypeTree(Template(List(Ident(BaseUniverseClass), Ident(SingletonClass)), emptyValDef, List()))))),
List(List(ValDef(Modifiers(PARAM), nme.MIRROR_UNTYPED, AppliedTypeTree(Ident(MirrorOfClass), List(Ident(tparamu))), EmptyTree))),
SelectFromTypeTree(Ident(tparamu), tpnme.Tree),
Block(
ValDef(NoMods, nme.UNIVERSE_SHORT, Ident(ApiUniverseClass), TypeApply(Select(Select(Ident(nme.MIRROR_UNTYPED), nme.universe), nme.asInstanceOf_), List(Ident(ApiUniverseClass)))),
ValDef(NoMods, nme.MIRROR_SHORT, Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror), TypeApply(Select(Ident(nme.MIRROR_UNTYPED), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror)))),
TypeApply(Select(Apply(TypeApply(Ident(reifierName), List(SingletonTypeTree(Ident(nme.UNIVERSE_SHORT)))), List(Ident(nme.MIRROR_SHORT))), nme.asInstanceOf_), List(SelectFromTypeTree(Ident(tparamu), tpnme.Tree)))
))
)
case tpnme.REIFY_TREECREATOR_PREFIX => (TreeCreatorClass, nme.apply, SelectFromTypeTree(Ident(tparamu), tpnme.Tree), BaseUniverseClass)
case _ => throw new Error(s"unexpected flavor $flavor")
}
val reifierBody = {
Expand Down Expand Up @@ -98,8 +77,7 @@ trait Extractors {
Template(List(Ident(reifierBase)),
emptyValDef,
List(
DefDef(NoMods, nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(()))))
) ++ reifierPreamble ++ List(
DefDef(NoMods, nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))),
DefDef(NoMods,
reifierName,
List(TypeDef(Modifiers(PARAM), tparamu, List(), TypeBoundsTree(Ident(NothingClass), CompoundTypeTree(Template(List(Ident(reifierUniverse), Ident(SingletonClass)), emptyValDef, List()))))),
Expand Down Expand Up @@ -128,7 +106,7 @@ trait Extractors {
case Block(
List(udef @ ValDef(_, _, _, universe), mdef @ ValDef(_, _, _, mirror)),
Apply(
Apply(TypeApply(_, List(ttpe @ TypeTree())), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, _, DefDef(_, _, _, _, _, Block(_ :: _ :: symbolTable1, rtree)))))), _))),
Apply(TypeApply(_, List(ttpe @ TypeTree())), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, DefDef(_, _, _, _, _, Block(_ :: _ :: symbolTable1, rtree)))))), _))),
// todo. doesn't take into account optimizations such as $u.TypeTag.Int or the upcoming closure optimization
List(Apply(TypeApply(tagFactory @ Select(_, _), _), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, DefDef(_, _, _, _, _, Block(_ :: _ :: symbolTable2, rtpe)))))), _))))))
if udef.name == nme.UNIVERSE_SHORT && mdef.name == nme.MIRROR_SHORT =>
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/reflect/FastTrack.scala
Expand Up @@ -38,7 +38,7 @@ trait FastTrack {
MacroInternal_materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeClassTag(u, tt.tpe) }
MacroInternal_materializeAbsTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) }
MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) }
ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
BaseUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree }
StringContext_f bindTo { case (c, app@Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args, app.pos) }
registry
Expand Down
2 changes: 2 additions & 0 deletions src/library/scala/reflect/base/Base.scala
Expand Up @@ -466,6 +466,8 @@ class Base extends Universe { self =>

def treeToString(tree: Tree) = s"<tree ${tree.getClass}>"

def treeType(tree: Tree) = NoType

trait TermTree extends Tree

trait TypTree extends Tree
Expand Down
Expand Up @@ -4,9 +4,7 @@
*/

package scala.reflect
package api

import scala.reflect.base.TreeCreator
package base

trait Exprs { self: Universe =>

Expand Down Expand Up @@ -46,7 +44,7 @@ trait Exprs { self: Universe =>
// !!! remove when we have improved type inference for singletons
// search for .type] to find other instances
lazy val staticTpe: Type = implicitly[AbsTypeTag[T]].tpe
def actualTpe: Type = tree.tpe
def actualTpe: Type = treeType(tree)

def splice: T = throw new UnsupportedOperationException("""
|the function you're calling has not been spliced by the compiler.
Expand Down
3 changes: 3 additions & 0 deletions src/library/scala/reflect/base/Trees.scala
Expand Up @@ -34,6 +34,9 @@ trait Trees { self: Universe =>
/** Obtains string representation of a tree */
protected def treeToString(tree: Tree): String

/** Obtains the type of the tree (we intentionally don't expose `tree.tpe` in base) */
protected def treeType(tree: Tree): Type

/** Tree is the basis for scala's abstract syntax. The nodes are
* implemented as case classes, and the parameters which initialize
* a given tree are immutable: however Trees have several mutable
Expand Down
50 changes: 49 additions & 1 deletion src/library/scala/reflect/base/Universe.scala
Expand Up @@ -10,9 +10,57 @@ abstract class Universe extends Symbols
with Constants
with AnnotationInfos
with Positions
with Exprs
with TypeTags
with TagInterop
with StandardDefinitions
with StandardNames
with BuildUtils
with Mirrors
with Mirrors
{
/** Given an expression, generate a tree that when compiled and executed produces the original tree.
* The produced tree will be bound to the Universe it was called from.
*
* For instance, given the abstract syntax tree representation of the <[ x + 1 ]> expression:
*
* {{{
* Apply(Select(Ident("x"), "+"), List(Literal(Constant(1))))
* }}}
*
* The reifier transforms it to the following expression:
*
* {{{
* <[
* val $u: u.type = u // where u is a reference to the Universe that calls the reify
* $u.Expr[Int]($u.Apply($u.Select($u.Ident($u.newFreeVar("x", <Int>, x), "+"), List($u.Literal($u.Constant(1))))))
* ]>
* }}}
*
* Reification performs expression splicing (when processing Expr.splice)
* and type splicing (for every type T that has a TypeTag[T] implicit in scope):
*
* {{{
* val two = mirror.reify(2) // Literal(Constant(2))
* val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("$plus")), List(two.tree))
*
* def macroImpl[T](c: Context) = {
* ...
* // T here is just a type parameter, so the tree produced by reify won't be of much use in a macro expansion
* // however, if T were annotated with c.TypeTag (which would declare an implicit parameter for macroImpl)
* // then reification would subtitute T with the TypeTree that was used in a TypeApply of this particular macro invocation
* val factory = c.reify{ new Queryable[T] }
* ...
* }
* }}}
*
* The transformation looks mostly straightforward, but it has its tricky parts:
* * Reifier retains symbols and types defined outside the reified tree, however
* locally defined entities get erased and replaced with their original trees
* * Free variables are detected and wrapped in symbols of the type FreeVar
* * Mutable variables that are accessed from a local function are wrapped in refs
* * 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
*/
// implementation is magically hardwired to `scala.reflect.reify.Taggers`
def reify[T](expr: T): Expr[T] = ??? // macro
}
2 changes: 2 additions & 0 deletions src/reflect/scala/reflect/api/Trees.scala
Expand Up @@ -109,6 +109,8 @@ trait Trees extends base.Trees { self: Universe =>
def duplicate: this.type
}

override protected def treeType(tree: Tree) = tree.tpe

override type TermTree >: Null <: Tree with TermTreeApi

/** The API that all term trees support */
Expand Down
49 changes: 0 additions & 49 deletions src/reflect/scala/reflect/api/Universe.scala
Expand Up @@ -14,53 +14,4 @@ abstract class Universe extends base.Universe
with StandardDefinitions
with StandardNames
with Importers
with Exprs
with AnnotationInfos
{

/** Given an expression, generate a tree that when compiled and executed produces the original tree.
* The produced tree will be bound to the Universe it was called from.
*
* For instance, given the abstract syntax tree representation of the <[ x + 1 ]> expression:
*
* {{{
* Apply(Select(Ident("x"), "+"), List(Literal(Constant(1))))
* }}}
*
* The reifier transforms it to the following expression:
*
* {{{
* <[
* val $u: u.type = u // where u is a reference to the Universe that calls the reify
* $u.Expr[Int]($u.Apply($u.Select($u.Ident($u.newFreeVar("x", <Int>, x), "+"), List($u.Literal($u.Constant(1))))))
* ]>
* }}}
*
* Reification performs expression splicing (when processing Expr.splice)
* and type splicing (for every type T that has a TypeTag[T] implicit in scope):
*
* {{{
* val two = mirror.reify(2) // Literal(Constant(2))
* val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("$plus")), List(two.tree))
*
* def macroImpl[T](c: Context) = {
* ...
* // T here is just a type parameter, so the tree produced by reify won't be of much use in a macro expansion
* // however, if T were annotated with c.TypeTag (which would declare an implicit parameter for macroImpl)
* // then reification would subtitute T with the TypeTree that was used in a TypeApply of this particular macro invocation
* val factory = c.reify{ new Queryable[T] }
* ...
* }
* }}}
*
* The transformation looks mostly straightforward, but it has its tricky parts:
* * Reifier retains symbols and types defined outside the reified tree, however
* locally defined entities get erased and replaced with their original trees
* * Free variables are detected and wrapped in symbols of the type FreeVar
* * Mutable variables that are accessed from a local function are wrapped in refs
* * 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
*/
// implementation is magically hardwired to `scala.reflect.reify.Taggers`
def reify[T](expr: T): Expr[T] = ??? // macro
}
13 changes: 6 additions & 7 deletions src/reflect/scala/reflect/internal/Definitions.scala
Expand Up @@ -471,11 +471,11 @@ trait Definitions extends api.StandardDefinitions {
lazy val OptManifestClass = requiredClass[scala.reflect.OptManifest[_]]
lazy val NoManifest = requiredModule[scala.reflect.NoManifest.type]

lazy val ExprsClass = getClassIfDefined("scala.reflect.api.Exprs") // defined in scala-reflect.jar, so we need to be careful
lazy val ExprClass = if (ExprsClass != NoSymbol) getMemberClass(ExprsClass, tpnme.Expr) else NoSymbol
def ExprSplice = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.splice) else NoSymbol
def ExprValue = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.value) else NoSymbol
lazy val ExprModule = if (ExprsClass != NoSymbol) getMemberModule(ExprsClass, nme.Expr) else NoSymbol
lazy val ExprsClass = requiredClass[scala.reflect.base.Exprs]
lazy val ExprClass = getMemberClass(ExprsClass, tpnme.Expr)
def ExprSplice = getMemberMethod(ExprClass, nme.splice)
def ExprValue = getMemberMethod(ExprClass, nme.value)
lazy val ExprModule = getMemberModule(ExprsClass, nme.Expr)

lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]]
lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]]
Expand All @@ -486,8 +486,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val TypeTagModule = getMemberModule(TypeTagsClass, nme.TypeTag)

lazy val BaseUniverseClass = requiredClass[scala.reflect.base.Universe]
lazy val ApiUniverseClass = getClassIfDefined("scala.reflect.api.Universe") // defined in scala-reflect.jar, so we need to be careful
def ApiUniverseReify = if (ApiUniverseClass != NoSymbol) getMemberMethod(ApiUniverseClass, nme.reify) else NoSymbol
def BaseUniverseReify = getMemberMethod(BaseUniverseClass, nme.reify)
lazy val JavaUniverseClass = getClassIfDefined("scala.reflect.api.JavaUniverse") // defined in scala-reflect.jar, so we need to be careful

lazy val MirrorOfClass = requiredClass[scala.reflect.base.MirrorOf[_]]
Expand Down

0 comments on commit f7164b8

Please sign in to comment.