mirror of https://github.com/sbt/sbt.git
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:
parent
087e386c99
commit
a3d6a5d5b3
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue