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`).
|
/** 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.
|
* 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. */
|
* 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,_}
|
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*/
|
* (The current implementation uses Context.fresh, which increments*/
|
||||||
def freshTermName(prefix: String) = newTermName(ctx.fresh("$" + prefix))
|
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,
|
/** Constructs a new, local ValDef with the given Type, a unique name,
|
||||||
* the same position as `sym`, and an empty implementation (no rhs). */
|
* the same position as `sym`, and an empty implementation (no rhs). */
|
||||||
def freshValDef(tpe: Type, sym: Symbol): ValDef =
|
def freshValDef(tpe: Type, sym: Symbol): ValDef =
|
||||||
{
|
{
|
||||||
val vd = localValDef(typeTree(tpe), EmptyTree)
|
val vd = localValDef(TypeTree(tpe), EmptyTree)
|
||||||
vd setPos getPos(sym)
|
vd setPos getPos(sym)
|
||||||
vd
|
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`. */
|
/** 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]
|
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` */
|
/** The type representing the type constructor `[X] X` */
|
||||||
val idTC: Type =
|
val idTC: Type =
|
||||||
|
|
@ -65,28 +63,27 @@ final class ContextUtil[C <: Context with Singleton](val ctx: C)
|
||||||
val tvar = newTypeVariable(NoSymbol)
|
val tvar = newTypeVariable(NoSymbol)
|
||||||
polyType(tvar :: Nil, refVar(tvar))
|
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. */
|
/** 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 = newTypeVariable(owner)
|
||||||
val tc = owner.asInstanceOf[global.Symbol].newSyntheticTypeParam()
|
val arg = newTypeVariable(tc, "x")
|
||||||
val arg = tc.newSyntheticTypeParam("x", 0L)
|
tc.setTypeSignature(PolyType(arg :: Nil, emptyTypeBounds))
|
||||||
tc.setInfo(global.PolyType(arg :: Nil, global.TypeBounds.empty)).asInstanceOf[ctx.universe.Symbol]
|
tc
|
||||||
}
|
}
|
||||||
|
def emptyTypeBounds: TypeBounds = TypeBounds(definitions.NothingClass.asType, definitions.AnyClass.asType)
|
||||||
|
|
||||||
/** Returns the Symbol that references the statically accessible singleton `i`. */
|
/** 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 =
|
def singleton[T <: AnyRef with Singleton](i: T)(implicit it: ctx.TypeTag[i.type]): Symbol =
|
||||||
it.tpe match {
|
it.tpe match {
|
||||||
case SingleType(_, sym) if !sym.isFreeTerm && sym.isStatic => sym
|
case SingleType(_, sym) if !sym.isFreeTerm && sym.isStatic => sym
|
||||||
case x => error("Instance must be static (was " + x + ").")
|
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`. */
|
/** Returns the symbol for the non-private method named `name` for the class/module `obj`. */
|
||||||
def method(obj: Symbol, name: String): Symbol = {
|
def method(obj: Symbol, name: String): Symbol = obj.typeSignature.nonPrivateMember(newTermName(name))
|
||||||
val global: Global = ctx.universe.asInstanceOf[Global]
|
|
||||||
obj.asInstanceOf[global.Symbol].info.nonPrivateMember(global.newTermName(name)).asInstanceOf[ctx.universe.Symbol]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a Type representing the type constructor tcp.<name>. For example, given
|
/** 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
|
* `object Demo { type M[x] = List[x] }`, the call `extractTC(Demo, "M")` will return a type representing
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,6 @@ object Instance
|
||||||
{
|
{
|
||||||
import c.universe.{Apply=>ApplyTree,_}
|
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 util = ContextUtil[c.type](c)
|
||||||
val mTC: Type = util.extractTC(i, InstanceTCName)
|
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
|
// constructs a ValDef with a parameter modifier, a unique name, with the provided Type and with an empty rhs
|
||||||
def freshMethodParameter(tpe: Type): ValDef =
|
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 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
|
/* Local definitions in the macro. This is used to ensure
|
||||||
* references are to M instances defined outside of the macro call.*/
|
* 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
|
// 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.
|
// 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 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 id @ Ident(name) if illegalReference(id.symbol) => c.error(id.pos, DynamicReferenceError)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
// adds the symbols for all non-Ident subtrees to `defs`.
|
// adds the symbols for all non-Ident subtrees to `defs`.
|
||||||
val defSearch = visitor {
|
val defSearch: Tree => Unit = {
|
||||||
case _: Ident => ()
|
case _: Ident => ()
|
||||||
case tree => if(tree.symbol ne null) defs += tree.symbol;
|
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
|
// no inputs, so construct M[T] via Instance.pure or pure+flatten
|
||||||
def pure(body: Tree): Tree =
|
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)
|
val p = ApplyTree(typeApplied, Function(Nil, body) :: Nil)
|
||||||
if(t.isLeft) p else flatten(p)
|
if(t.isLeft) p else flatten(p)
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +154,7 @@ object Instance
|
||||||
// the returned Tree will have type M[T]
|
// the returned Tree will have type M[T]
|
||||||
def flatten(m: Tree): Tree =
|
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)
|
ApplyTree(typedFlatten, m :: Nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +163,7 @@ object Instance
|
||||||
{
|
{
|
||||||
val variable = input.local
|
val variable = input.local
|
||||||
val param = ValDef(parameterModifiers, variable.name, variable.tpt, EmptyTree)
|
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)
|
val mapped = ApplyTree(typeApplied, input.expr :: Function(param :: Nil, body) :: Nil)
|
||||||
if(t.isLeft) mapped else flatten(mapped)
|
if(t.isLeft) mapped else flatten(mapped)
|
||||||
}
|
}
|
||||||
|
|
@ -189,8 +175,8 @@ object Instance
|
||||||
val param = freshMethodParameter( appliedType(result.representationC, util.idTC :: Nil) )
|
val param = freshMethodParameter( appliedType(result.representationC, util.idTC :: Nil) )
|
||||||
val bindings = result.extract(param)
|
val bindings = result.extract(param)
|
||||||
val f = Function(param :: Nil, Block(bindings, body))
|
val f = Function(param :: Nil, Block(bindings, body))
|
||||||
val ttt = typeTree(treeType)
|
val ttt = TypeTree(treeType)
|
||||||
val typedApp = TypeApply(Select(instance, ApplyName), typeTree(result.representationC) :: ttt :: Nil)
|
val typedApp = TypeApply(Select(instance, ApplyName), TypeTree(result.representationC) :: ttt :: Nil)
|
||||||
val app = ApplyTree(ApplyTree(typedApp, result.input :: f :: Nil), result.alistInstance :: Nil)
|
val app = ApplyTree(ApplyTree(typedApp, result.input :: f :: Nil), result.alistInstance :: Nil)
|
||||||
if(t.isLeft) app else flatten(app)
|
if(t.isLeft) app else flatten(app)
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +188,7 @@ object Instance
|
||||||
// the bound value of the input
|
// the bound value of the input
|
||||||
def addType(tpe: Type, qual: Tree): Tree =
|
def addType(tpe: Type, qual: Tree): Tree =
|
||||||
{
|
{
|
||||||
checkQual(qual)
|
qual.foreach(checkQual)
|
||||||
val vd = util.freshValDef(tpe, qual.symbol)
|
val vd = util.freshValDef(tpe, qual.symbol)
|
||||||
inputs ::= new Input(tpe, qual, vd)
|
inputs ::= new Input(tpe, qual, vd)
|
||||||
Ident(vd.name)
|
Ident(vd.name)
|
||||||
|
|
@ -223,7 +209,7 @@ object Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
// collects all definitions in the tree. used for finding illegal references
|
// collects all definitions in the tree. used for finding illegal references
|
||||||
defSearch(tree)
|
tree.foreach(defSearch)
|
||||||
|
|
||||||
// applies the transformation
|
// applies the transformation
|
||||||
// resetting attributes: a) must be local b) must be done
|
// resetting attributes: a) must be local b) must be done
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ object KListBuilder extends TupleBuilder
|
||||||
val kconsTC: Type = kconsTpe.typeConstructor
|
val kconsTC: Type = kconsTpe.typeConstructor
|
||||||
|
|
||||||
/** This is the L in the type function [L[x]] ... */
|
/** 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 */
|
/** Instantiates KCons[h, t <: KList[L], L], where L is the type constructor variable */
|
||||||
def kconsType(h: Type, t: Type): Type =
|
def kconsType(h: Type, t: Type): Type =
|
||||||
|
|
@ -52,7 +52,7 @@ object KListBuilder extends TupleBuilder
|
||||||
val representationC = PolyType(tcVariable :: Nil, klistType)
|
val representationC = PolyType(tcVariable :: Nil, klistType)
|
||||||
val resultType = appliedType(representationC, idTC :: Nil)
|
val resultType = appliedType(representationC, idTC :: Nil)
|
||||||
val input = klist
|
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))
|
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 input: Tree = mkTuple(inputs.map(_.expr))
|
||||||
val alistInstance: Tree = {
|
val alistInstance: Tree = {
|
||||||
val select = Select(Ident(alist), TupleMethodName + inputs.size.toString)
|
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)
|
def extract(param: ValDef): List[ValDef] = bindTuple(param, Nil, inputs.map(_.local), 1)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue