Task macro cleanup

* use normal TypeTree constructor
* remove unnecessary 'with Singleton' in macro utility
* integrate changes suggested by @xeno-by
* add refVar back and call asTypeConstructor instead of asType to refer to a type variable
This commit is contained in:
Mark Harrah 2012-08-01 16:20:03 -04:00
parent 087e386c99
commit a3d6a5d5b3
4 changed files with 27 additions and 44 deletions

View File

@ -14,7 +14,7 @@ object ContextUtil {
/** Utility methods for macros. Several methods assume that the context's universe is a full compiler (`scala.tools.nsc.Global`).
* This is not thread safe due to the underlying Context and related data structures not being thread safe.
* Use `ContextUtil[c.type](c)` to construct. */
final class ContextUtil[C <: Context with Singleton](val ctx: C)
final class ContextUtil[C <: Context](val ctx: C)
{
import ctx.universe.{Apply=>ApplyTree,_}
@ -31,13 +31,11 @@ final class ContextUtil[C <: Context with Singleton](val ctx: C)
* (The current implementation uses Context.fresh, which increments*/
def freshTermName(prefix: String) = newTermName(ctx.fresh("$" + prefix))
def typeTree(tpe: Type) = TypeTree().setType(tpe)
/** Constructs a new, local ValDef with the given Type, a unique name,
* the same position as `sym`, and an empty implementation (no rhs). */
def freshValDef(tpe: Type, sym: Symbol): ValDef =
{
val vd = localValDef(typeTree(tpe), EmptyTree)
val vd = localValDef(TypeTree(tpe), EmptyTree)
vd setPos getPos(sym)
vd
}
@ -54,10 +52,10 @@ final class ContextUtil[C <: Context with Singleton](val ctx: C)
}
/** Creates a new, synthetic type variable with the specified `owner`. */
def newTypeVariable(owner: Symbol): Symbol =
def newTypeVariable(owner: Symbol, prefix: String = "T0"): TypeSymbol =
{
val global: Global = ctx.universe.asInstanceOf[Global]
owner.asInstanceOf[global.Symbol].newSyntheticTypeParam().asInstanceOf[ctx.universe.Symbol]
owner.asInstanceOf[global.Symbol].newSyntheticTypeParam(prefix, 0L).asInstanceOf[ctx.universe.TypeSymbol]
}
/** The type representing the type constructor `[X] X` */
val idTC: Type =
@ -65,28 +63,27 @@ final class ContextUtil[C <: Context with Singleton](val ctx: C)
val tvar = newTypeVariable(NoSymbol)
polyType(tvar :: Nil, refVar(tvar))
}
/** A Type that references the given type variable. */
def refVar(variable: TypeSymbol): Type = variable.asTypeConstructor
/** Constructs a new, synthetic type variable that is a type constructor. For example, in type Y[L[x]], L is such a type variable. */
def newTCVariable(owner: Symbol): Symbol =
def newTCVariable(owner: Symbol): TypeSymbol =
{
val global: Global = ctx.universe.asInstanceOf[Global]
val tc = owner.asInstanceOf[global.Symbol].newSyntheticTypeParam()
val arg = tc.newSyntheticTypeParam("x", 0L)
tc.setInfo(global.PolyType(arg :: Nil, global.TypeBounds.empty)).asInstanceOf[ctx.universe.Symbol]
val tc = newTypeVariable(owner)
val arg = newTypeVariable(tc, "x")
tc.setTypeSignature(PolyType(arg :: Nil, emptyTypeBounds))
tc
}
def emptyTypeBounds: TypeBounds = TypeBounds(definitions.NothingClass.asType, definitions.AnyClass.asType)
/** Returns the Symbol that references the statically accessible singleton `i`. */
def singleton[T <: AnyRef with Singleton](i: T)(implicit it: ctx.TypeTag[i.type]): Symbol =
it.tpe match {
case SingleType(_, sym) if !sym.isFreeTerm && sym.isStatic => sym
case x => error("Instance must be static (was " + x + ").")
}
/** Constructs a Type that references the given type variable. */
def refVar(variable: Symbol): Type = typeRef(NoPrefix, variable, Nil)
/** Returns the symbol for the non-private method named `name` for the class/module `obj`. */
def method(obj: Symbol, name: String): Symbol = {
val global: Global = ctx.universe.asInstanceOf[Global]
obj.asInstanceOf[global.Symbol].info.nonPrivateMember(global.newTermName(name)).asInstanceOf[ctx.universe.Symbol]
}
def method(obj: Symbol, name: String): Symbol = obj.typeSignature.nonPrivateMember(newTermName(name))
/** Returns a Type representing the type constructor tcp.<name>. For example, given
* `object Demo { type M[x] = List[x] }`, the call `extractTC(Demo, "M")` will return a type representing

View File

@ -84,10 +84,6 @@ object Instance
implicit tt: c.TypeTag[T], mt: c.TypeTag[i.M[T]], it: c.TypeTag[i.type]): c.Expr[i.M[T]] =
{
import c.universe.{Apply=>ApplyTree,_}
import scala.tools.nsc.Global
// Used to access compiler methods not yet exposed via the reflection/macro APIs
val global: Global = c.universe.asInstanceOf[Global]
val util = ContextUtil[c.type](c)
val mTC: Type = util.extractTC(i, InstanceTCName)
@ -113,19 +109,9 @@ object Instance
// constructs a ValDef with a parameter modifier, a unique name, with the provided Type and with an empty rhs
def freshMethodParameter(tpe: Type): ValDef =
ValDef(parameterModifiers, freshTermName("p"), typeTree(tpe), EmptyTree)
ValDef(parameterModifiers, freshTermName("p"), TypeTree(tpe), EmptyTree)
def freshTermName(prefix: String) = newTermName(c.fresh("$" + prefix))
def typeTree(tpe: Type) = TypeTree().setType(tpe)
// constructs a function that applies f to each subtree of the input tree
def visitor(f: Tree => Unit): Tree => Unit =
{
val v: Transformer = new Transformer {
override def transform(tree: Tree): Tree = { f(tree); super.transform(tree) }
}
(tree: Tree) => v.transform(tree)
}
/* Local definitions in the macro. This is used to ensure
* references are to M instances defined outside of the macro call.*/
@ -137,13 +123,13 @@ object Instance
// a function that checks the provided tree for illegal references to M instances defined in the
// expression passed to the macro and for illegal dereferencing of M instances.
val checkQual = visitor {
val checkQual: Tree => Unit = {
case s @ ApplyTree(fun, qual :: Nil) => if(isWrapper(fun)) c.error(s.pos, DynamicDependencyError)
case id @ Ident(name) if illegalReference(id.symbol) => c.error(id.pos, DynamicReferenceError)
case _ => ()
}
// adds the symbols for all non-Ident subtrees to `defs`.
val defSearch = visitor {
val defSearch: Tree => Unit = {
case _: Ident => ()
case tree => if(tree.symbol ne null) defs += tree.symbol;
}
@ -160,7 +146,7 @@ object Instance
// no inputs, so construct M[T] via Instance.pure or pure+flatten
def pure(body: Tree): Tree =
{
val typeApplied = TypeApply(Select(instance, PureName), typeTree(treeType) :: Nil)
val typeApplied = TypeApply(Select(instance, PureName), TypeTree(treeType) :: Nil)
val p = ApplyTree(typeApplied, Function(Nil, body) :: Nil)
if(t.isLeft) p else flatten(p)
}
@ -168,7 +154,7 @@ object Instance
// the returned Tree will have type M[T]
def flatten(m: Tree): Tree =
{
val typedFlatten = TypeApply(Select(instance, FlattenName), typeTree(tt.tpe) :: Nil)
val typedFlatten = TypeApply(Select(instance, FlattenName), TypeTree(tt.tpe) :: Nil)
ApplyTree(typedFlatten, m :: Nil)
}
@ -177,7 +163,7 @@ object Instance
{
val variable = input.local
val param = ValDef(parameterModifiers, variable.name, variable.tpt, EmptyTree)
val typeApplied = TypeApply(Select(instance, MapName), variable.tpt :: typeTree(treeType) :: Nil)
val typeApplied = TypeApply(Select(instance, MapName), variable.tpt :: TypeTree(treeType) :: Nil)
val mapped = ApplyTree(typeApplied, input.expr :: Function(param :: Nil, body) :: Nil)
if(t.isLeft) mapped else flatten(mapped)
}
@ -189,8 +175,8 @@ object Instance
val param = freshMethodParameter( appliedType(result.representationC, util.idTC :: Nil) )
val bindings = result.extract(param)
val f = Function(param :: Nil, Block(bindings, body))
val ttt = typeTree(treeType)
val typedApp = TypeApply(Select(instance, ApplyName), typeTree(result.representationC) :: ttt :: Nil)
val ttt = TypeTree(treeType)
val typedApp = TypeApply(Select(instance, ApplyName), TypeTree(result.representationC) :: ttt :: Nil)
val app = ApplyTree(ApplyTree(typedApp, result.input :: f :: Nil), result.alistInstance :: Nil)
if(t.isLeft) app else flatten(app)
}
@ -202,7 +188,7 @@ object Instance
// the bound value of the input
def addType(tpe: Type, qual: Tree): Tree =
{
checkQual(qual)
qual.foreach(checkQual)
val vd = util.freshValDef(tpe, qual.symbol)
inputs ::= new Input(tpe, qual, vd)
Ident(vd.name)
@ -223,7 +209,7 @@ object Instance
}
// collects all definitions in the tree. used for finding illegal references
defSearch(tree)
tree.foreach(defSearch)
// applies the transformation
// resetting attributes: a) must be local b) must be done

View File

@ -24,7 +24,7 @@ object KListBuilder extends TupleBuilder
val kconsTC: Type = kconsTpe.typeConstructor
/** This is the L in the type function [L[x]] ... */
val tcVariable: Symbol = newTCVariable(NoSymbol)
val tcVariable: TypeSymbol = newTCVariable(NoSymbol)
/** Instantiates KCons[h, t <: KList[L], L], where L is the type constructor variable */
def kconsType(h: Type, t: Type): Type =
@ -52,7 +52,7 @@ object KListBuilder extends TupleBuilder
val representationC = PolyType(tcVariable :: Nil, klistType)
val resultType = appliedType(representationC, idTC :: Nil)
val input = klist
val alistInstance = TypeApply(Select(Ident(alist), "klist"), typeTree(representationC) :: Nil)
val alistInstance = TypeApply(Select(Ident(alist), "klist"), TypeTree(representationC) :: Nil)
def extract(param: ValDef) = bindKList(param, Nil, inputs.map(_.local))
}
}

View File

@ -35,7 +35,7 @@ object TupleNBuilder extends TupleBuilder
val input: Tree = mkTuple(inputs.map(_.expr))
val alistInstance: Tree = {
val select = Select(Ident(alist), TupleMethodName + inputs.size.toString)
TypeApply(select, inputs.map(in => typeTree(in.tpe)))
TypeApply(select, inputs.map(in => TypeTree(in.tpe)))
}
def extract(param: ValDef): List[ValDef] = bindTuple(param, Nil, inputs.map(_.local), 1)