diff --git a/main/settings/src/main/scala/sbt/std/InputWrapper.scala b/main/settings/src/main/scala/sbt/std/InputWrapper.scala index 7644d3f2a..b5ada74ce 100644 --- a/main/settings/src/main/scala/sbt/std/InputWrapper.scala +++ b/main/settings/src/main/scala/sbt/std/InputWrapper.scala @@ -68,6 +68,7 @@ object InputWrapper sel.setPos(pos) // need to set the position on Select, because that is where the compileTimeOnly check looks val tree = ApplyTree(TypeApply(sel, TypeTree(tpe) :: Nil), ts.tree :: Nil) tree.setPos(ts.tree.pos) + tree.setType(tpe) c.Expr[T](tree) } diff --git a/main/settings/src/main/scala/sbt/std/TaskMacro.scala b/main/settings/src/main/scala/sbt/std/TaskMacro.scala index 94b4a562d..b4789247c 100644 --- a/main/settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main/settings/src/main/scala/sbt/std/TaskMacro.scala @@ -74,10 +74,10 @@ object TaskMacro final val InputTaskCreateDynName = "createDyn" final val InputTaskCreateFreeName = "createFree" - def taskMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Initialize[Task[T]]] = + def taskMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Initialize[Task[T]]] = Instance.contImpl[T,Id](c, FullInstance, FullConvert, MixedBuilder)(Left(t), Instance.idTransform[c.type]) - def taskDynMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Initialize[Task[T]]]): c.Expr[Initialize[Task[T]]] = + def taskDynMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Initialize[Task[T]]]): c.Expr[Initialize[Task[T]]] = Instance.contImpl[T,Id](c, FullInstance, FullConvert, MixedBuilder)(Right(t), Instance.idTransform[c.type]) /** Implementation of := macro for settings. */ @@ -177,7 +177,7 @@ object TaskMacro private[this] def transformMacroImpl(c: Context)(init: c.Tree)(newName: String): c.Tree = { import c.universe.{Apply,ApplyTag,newTermName,Select,SelectTag} - val target = + val target = c.macroApplication match { case Apply(Select(prefix, _), _) => prefix case x => ContextUtil.unexpectedTree(x) @@ -223,7 +223,7 @@ object TaskMacro private[this] def inputTaskMacro0[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Initialize[InputTask[T]]] = iInitializeMacro(c)(t) { et => - val pt = iParserMacro(c)(et) { pt => + val pt = iParserMacro(c)(et) { pt => iTaskMacro(c)(pt) } c.universe.reify { InputTask.make(pt.splice) } @@ -269,22 +269,22 @@ object TaskMacro case _ => Converted.NotApplicable } val util = ContextUtil[c.type](c) - util.transformWrappers(t, (nme,tpe,tree) => expand(nme,tpe,tree)) + util.transformWrappers(t, (nme,tpe,tree,original) => expand(nme,tpe,tree)) } - + private[this] def iParserMacro[M[_], T](c: Context)(t: c.Expr[T])(f: c.Expr[T] => c.Expr[M[T]])(implicit tt: c.WeakTypeTag[T], mt: c.WeakTypeTag[M[T]]): c.Expr[State => Parser[M[T]]] = { val inner: Transform[c.type,M] = new Transform[c.type,M] { def apply(in: c.Tree): c.Tree = f(c.Expr[T](in)).tree } Instance.contImpl[T,M](c, ParserInstance, ParserConvert, MixedBuilder)(Left(t), inner) } - + private[this] def iTaskMacro[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Task[T]] = Instance.contImpl[T,Id](c, TaskInstance, TaskConvert, MixedBuilder)(Left(t), Instance.idTransform) - private[this] def inputTaskDynMacro0[T: c.WeakTypeTag](c: Context)(t: c.Expr[Initialize[Task[T]]]): c.Expr[Initialize[InputTask[T]]] = + private[this] def inputTaskDynMacro0[T: c.WeakTypeTag](c: Context)(t: c.Expr[Initialize[Task[T]]]): c.Expr[Initialize[InputTask[T]]] = { import c.universe.{Apply=>ApplyTree,_} - + val tag = implicitly[c.WeakTypeTag[T]] val util = ContextUtil[c.type](c) val it = Ident(util.singleton(InputTask)) @@ -295,9 +295,13 @@ object TaskMacro val defs = util.collectDefs(ttree, isAnyWrapper) val checkQual = util.checkReferences(defs, isAnyWrapper) + // the Symbol for the anonymous function passed to the appropriate Instance.map/flatMap/pure method + // this Symbol needs to be known up front so that it can be used as the owner of synthetic vals + val functionSym = util.functionSymbol(ttree.pos) var result: Option[(Tree, Type, ValDef)] = None - def subWrapper(tpe: Type, qual: Tree): Tree = + // original is the Tree being replaced. It is needed for preserving attributes. + def subWrapper(tpe: Type, qual: Tree, original: Tree): Tree = if(result.isDefined) { c.error(qual.pos, "Implementation restriction: a dynamic InputTask can only have a single input parser.") @@ -306,9 +310,9 @@ object TaskMacro else { qual.foreach(checkQual) - val vd = util.freshValDef(tpe, qual.symbol) // val $x: + val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) // val $x: result = Some( (qual, tpe, vd) ) - val tree = util.refVal(vd, qual.pos) // $x + val tree = util.refVal(original, vd) // $x tree.setPos(qual.pos) // position needs to be set so that wrapKey passes the position onto the wrapper assert(tree.tpe != null, "Null type: " + tree) tree.setType(tpe) @@ -335,25 +339,25 @@ object TaskMacro taskMacroImpl[I](c)( c.Expr[I](tx) ) def wrapTag[I: WeakTypeTag]: WeakTypeTag[Initialize[Task[I]]] = weakTypeTag - def sub(name: String, tpe: Type, qual: Tree): Converted[c.type] = + def sub(name: String, tpe: Type, qual: Tree, selection: Tree): Converted[c.type] = { val tag = c.WeakTypeTag[T](tpe) InitParserConvert(c)(name, qual)(tag) transform { tree => - subWrapper(tpe, tree) + subWrapper(tpe, tree, selection) } } - val tx = util.transformWrappers(ttree, (n,tpe,tree) => sub(n,tpe,tree)) + val tx = util.transformWrappers(ttree, (n,tpe,tree,replace) => sub(n,tpe,tree,replace)) result match { case Some((p, tpe, param)) => - val fCore = Function(param :: Nil, tx) + val fCore = util.createFunction(param :: Nil, tx, functionSym) val bodyTpe = wrapTag(tag).tpe val fTpe = util.functionType(tpe :: Nil, bodyTpe) val fTag = c.WeakTypeTag[Any](fTpe) // don't know the actual type yet, so use Any - val fInit = c.resetLocalAttrs( expandTask(false, fCore)(fTag).tree ) + val fInit = expandTask(false, fCore)(fTag).tree inputTaskCreate(InputTaskCreateDynName, tpe, tag.tpe, p, fInit) case None => - val init = c.resetLocalAttrs( expandTask[T](true, tx).tree ) + val init = expandTask[T](true, tx).tree inputTaskCreateFree(tag.tpe, init) } } @@ -362,10 +366,10 @@ object TaskMacro object PlainTaskMacro { def task[T](t: T): Task[T] = macro taskImpl[T] - def taskImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Task[T]] = + def taskImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Task[T]] = Instance.contImpl[T,Id](c, TaskInstance, TaskConvert, MixedBuilder)(Left(t), Instance.idTransform[c.type]) def taskDyn[T](t: Task[T]): Task[T] = macro taskDynImpl[T] - def taskDynImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]]): c.Expr[Task[T]] = + def taskDynImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]]): c.Expr[Task[T]] = Instance.contImpl[T,Id](c, TaskInstance, TaskConvert, MixedBuilder)(Right(t), Instance.idTransform[c.type]) } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 5a4b74a3a..f42374f1d 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -62,7 +62,7 @@ object Defaults extends BuildCommon scalaOrganization :== ScalaArtifacts.Organization, buildDependencies <<= Classpaths.constructBuildDependencies, taskTemporaryDirectory := { val dir = IO.createTemporaryDirectory; dir.deleteOnExit(); dir }, - onComplete := { val dir = taskTemporaryDirectory.value; () => IO.delete(dir); IO.createDirectory(dir) }, + onComplete := { val dir = taskTemporaryDirectory.value; () => {IO.delete(dir); IO.createDirectory(dir) }}, concurrentRestrictions <<= defaultRestrictions, parallelExecution :== true, sbtVersion := appConfiguration.value.provider.id.version, @@ -459,9 +459,7 @@ object Defaults extends BuildCommon { val parser = loadForParser(definedTestNames)( (s, i) => testOnlyParser(s, i getOrElse Nil) ) Def.inputTaskDyn { - val res = parser.parsed - val selected = res._1 - val frameworkOptions = res._2 + val (selected, frameworkOptions) = parser.parsed val s = streams.value val filter = testFilter.value val config = testExecution.value @@ -647,9 +645,7 @@ object Defaults extends BuildCommon import DefaultParsers._ val parser = loadForParser(discoveredMainClasses)( (s, names) => runMainParser(s, names getOrElse Nil) ) Def.inputTask { - val res = parser.parsed - val mainClass = res._1 - val args = res._2 + val (mainClass, args) = parser.parsed toError(scalaRun.value.run(mainClass, data(classpath.value), args, streams.value.log)) } } diff --git a/sbt/src/sbt-test/project/setting-macro/build.sbt b/sbt/src/sbt-test/project/setting-macro/build.sbt new file mode 100644 index 000000000..d48af8bc9 --- /dev/null +++ b/sbt/src/sbt-test/project/setting-macro/build.sbt @@ -0,0 +1,17 @@ + import complete.DefaultParsers._ + +name := { + // verify lazy vals are handled (#952) + lazy val x = "sdf" + x +} + +lazy val demo = inputKey[String]("sample") + +def parser: complete.Parser[(Int,String)] = token(Space ~> IntBasic <~ Space) ~ token("red") + +demo := { + // verify pattern match on the lhs is handled (#994) + val (n, s) = parser.parsed + s * n +} diff --git a/sbt/src/sbt-test/project/setting-macro/test b/sbt/src/sbt-test/project/setting-macro/test new file mode 100644 index 000000000..1752d68bb --- /dev/null +++ b/sbt/src/sbt-test/project/setting-macro/test @@ -0,0 +1,4 @@ +# this test is currently just to verify the project is loaded successfully + +# ensure the project is loaded +> demo 3 red \ No newline at end of file diff --git a/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala b/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala index dffc5e0c6..381674e47 100644 --- a/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala +++ b/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala @@ -35,10 +35,15 @@ 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](val ctx: C) +final class ContextUtil[C <: Context](val ctx: C) { import ctx.universe.{Apply=>ApplyTree,_} + val powerContext = ctx.asInstanceOf[reflect.macros.runtime.Context] + val global: powerContext.universe.type = powerContext.universe + def callsiteTyper: global.analyzer.Typer = powerContext.callsiteTyper + val initialOwner: Symbol = callsiteTyper.context.owner.asInstanceOf[ctx.universe.Symbol] + lazy val alistType = ctx.typeOf[AList[KList]] lazy val alist: Symbol = alistType.typeSymbol.companionSymbol lazy val alistTC: Type = alistType.typeConstructor @@ -52,12 +57,15 @@ final class ContextUtil[C <: Context](val ctx: C) * (The current implementation uses Context.fresh, which increments*/ def freshTermName(prefix: String) = newTermName(ctx.fresh("$" + prefix)) - /** 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 = + /** Constructs a new, synthetic, local ValDef Type `tpe`, a unique name, + * Position `pos`, an empty implementation (no rhs), and owned by `owner`. */ + def freshValDef(tpe: Type, pos: Position, owner: Symbol): ValDef = { - val vd = localValDef(TypeTree(tpe), EmptyTree) - vd setPos getPos(sym) + val SYNTHETIC = (1 << 21).toLong.asInstanceOf[FlagSet] + val sym = owner.newTermSymbol(freshTermName("q"), pos, SYNTHETIC) + setInfo(sym, tpe) + val vd = ValDef(sym, EmptyTree) + vd.setPos(pos) vd } @@ -65,7 +73,7 @@ final class ContextUtil[C <: Context](val ctx: C) /** Collects all definitions in the tree for use in checkReferences. * This excludes definitions in wrapped expressions because checkReferences won't allow nested dereferencing anyway. */ - def collectDefs(tree: Tree, isWrapper: (String, Type, Tree) => Boolean): collection.Set[Symbol] = + def collectDefs(tree: Tree, isWrapper: (String, Type, Tree) => Boolean): collection.Set[Symbol] = { val defs = new collection.mutable.HashSet[Symbol] // adds the symbols for all non-Ident subtrees to `defs`. @@ -106,17 +114,17 @@ final class ContextUtil[C <: Context](val ctx: C) /** Constructs a tuple value of the right TupleN type from the provided inputs.*/ def mkTuple(args: List[Tree]): Tree = - { - val global: Global = ctx.universe.asInstanceOf[Global] global.gen.mkTuple(args.asInstanceOf[List[global.Tree]]).asInstanceOf[ctx.universe.Tree] - } + + def setSymbol[Tree](t: Tree, sym: Symbol): Unit = + t.asInstanceOf[global.Tree].setSymbol(sym.asInstanceOf[global.Symbol]) + def setInfo[Tree](sym: Symbol, tpe: Type): Unit = + sym.asInstanceOf[global.Symbol].setInfo(tpe.asInstanceOf[global.Type]) /** Creates a new, synthetic type variable with the specified `owner`. */ def newTypeVariable(owner: Symbol, prefix: String = "T0"): TypeSymbol = - { - val global: Global = ctx.universe.asInstanceOf[Global] owner.asInstanceOf[global.Symbol].newSyntheticTypeParam(prefix, 0L).asInstanceOf[ctx.universe.TypeSymbol] - } + /** The type representing the type constructor `[X] X` */ lazy val idTC: Type = { @@ -136,21 +144,42 @@ final class ContextUtil[C <: Context](val ctx: C) /** >: Nothing <: Any */ def emptyTypeBounds: TypeBounds = TypeBounds(definitions.NothingClass.toType, definitions.AnyClass.toType) + /** Creates a new anonymous function symbol with Position `pos`. */ + def functionSymbol(pos: Position): Symbol = + callsiteTyper.context.owner.newAnonymousFunctionValue(pos.asInstanceOf[global.Position]).asInstanceOf[ctx.universe.Symbol] + def functionType(args: List[Type], result: Type): Type = { - val global: Global = ctx.universe.asInstanceOf[Global] val tpe = global.definitions.functionType(args.asInstanceOf[List[global.Type]], result.asInstanceOf[global.Type]) tpe.asInstanceOf[Type] } - /** Create a Tree that references the `val` represented by `vd`. */ - def refVal(vd: ValDef, pos: Position): Tree = + /** Create a Tree that references the `val` represented by `vd`, copying attributes from `replaced`. */ + def refVal(replaced: Tree, vd: ValDef): Tree = + treeCopy.Ident(replaced, vd.name).setSymbol(vd.symbol) + + /** Creates a Function tree using `functionSym` as the Symbol and changing `initialOwner` to `functionSym` in `body`.*/ + def createFunction(params: List[ValDef], body: Tree, functionSym: Symbol): Tree = { - val t = Ident(vd.name) - assert(vd.tpt.tpe != null, "val type is null: " + vd + ", tpt: " + vd.tpt.tpe) - t.setType(vd.tpt.tpe) - t.setPos(pos) - t + changeOwner(body, initialOwner, functionSym) + val f = Function(params, body) + setSymbol(f, functionSym) + f + } + + def changeOwner(tree: Tree, prev: Symbol, next: Symbol): Unit = + new ChangeOwnerAndModuleClassTraverser(prev.asInstanceOf[global.Symbol], next.asInstanceOf[global.Symbol]).traverse(tree.asInstanceOf[global.Tree]) + + // Workaround copied from scala/async:can be removed once https://github.com/scala/scala/pull/3179 is merged. + private[this] class ChangeOwnerAndModuleClassTraverser(oldowner: global.Symbol, newowner: global.Symbol) extends global.ChangeOwnerTraverser(oldowner, newowner) + { + override def traverse(tree: global.Tree) { + tree match { + case _: global.DefTree => change(tree.symbol.moduleClass) + case _ => + } + super.traverse(tree) + } } /** Returns the Symbol that references the statically accessible singleton `i`. */ @@ -164,7 +193,6 @@ final class ContextUtil[C <: Context](val ctx: C) /** 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] val ts: Type = obj.typeSignature val m: global.Symbol = ts.asInstanceOf[global.Type].nonPrivateMember(global.newTermName(name)) m.asInstanceOf[Symbol] @@ -176,7 +204,6 @@ final class ContextUtil[C <: Context](val ctx: C) **/ def extractTC(tcp: AnyRef with Singleton, name: String)(implicit it: ctx.TypeTag[tcp.type]): ctx.Type = { - val global: Global = ctx.universe.asInstanceOf[Global] val itTpe = it.tpe.asInstanceOf[global.Type] val m = itTpe.nonPrivateMember(global.newTypeName(name)) val tc = itTpe.memberInfo(m).asInstanceOf[ctx.universe.Type] @@ -187,8 +214,8 @@ final class ContextUtil[C <: Context](val ctx: C) /** Substitutes wrappers in tree `t` with the result of `subWrapper`. * A wrapper is a Tree of the form `f[T](v)` for which isWrapper(, , .target) returns true. * Typically, `f` is a `Select` or `Ident`. - * The wrapper is replaced with the result of `subWrapper(, )` */ - def transformWrappers(t: Tree, subWrapper: (String, Type, Tree) => Converted[ctx.type]): Tree = + * The wrapper is replaced with the result of `subWrapper(, , )` */ + def transformWrappers(t: Tree, subWrapper: (String, Type, Tree, Tree) => Converted[ctx.type]): Tree = { // the main tree transformer that replaces calls to InputWrapper.wrap(x) with // plain Idents that reference the actual input value @@ -197,7 +224,7 @@ final class ContextUtil[C <: Context](val ctx: C) override def transform(tree: Tree): Tree = tree match { - case ApplyTree(TypeApply(Select(_, nme), targ :: Nil), qual :: Nil) => subWrapper(nme.decoded, targ.tpe, qual) match { + case ApplyTree(TypeApply(Select(_, nme), targ :: Nil), qual :: Nil) => subWrapper(nme.decoded, targ.tpe, qual, tree) match { case Converted.Success(t, finalTx) => finalTx(t) case Converted.Failure(p,m) => ctx.abort(p, m) case _: Converted.NotApplicable[_] => super.transform(tree) diff --git a/util/appmacro/src/main/scala/sbt/appmacro/Instance.scala b/util/appmacro/src/main/scala/sbt/appmacro/Instance.scala index 5928df8bc..0de166b67 100644 --- a/util/appmacro/src/main/scala/sbt/appmacro/Instance.scala +++ b/util/appmacro/src/main/scala/sbt/appmacro/Instance.scala @@ -61,7 +61,7 @@ object Instance * These converted inputs are passed to `builder` as well as the list of these synthetic `ValDef`s. * The `TupleBuilder` instance constructs a tuple (Tree) from the inputs and defines the right hand side of the vals * that unpacks the tuple containing the results of the inputs. - * + * * The constructed tuple of inputs and the code that unpacks the results of the inputs are then passed to the `i`, * which is an implementation of `Instance` that is statically accessible. * An Instance defines a applicative functor associated with a specific type constructor and, if it implements MonadInstance as well, a monad. @@ -70,18 +70,18 @@ object Instance * while the full check for static accessibility is done at macro expansion time. * Note: Ideally, the types would verify that `i: MonadInstance` when `t.isRight`. * With the various dependent types involved, this is not worth it. - * + * * The `t` argument is the argument of the macro that will be transformed as described above. * If the macro that calls this method is for a multi-input map (app followed by map), * `t` should be the argument wrapped in Left. - * If this is for multi-input flatMap (app followed by flatMap), + * If this is for multi-input flatMap (app followed by flatMap), * this should be the argument wrapped in Right. */ def contImpl[T,N[_]](c: Context, i: Instance with Singleton, convert: Convert, builder: TupleBuilder)(t: Either[c.Expr[T], c.Expr[i.M[T]]], inner: Transform[c.type,N])( implicit tt: c.WeakTypeTag[T], nt: c.WeakTypeTag[N[T]], it: c.TypeTag[i.type]): c.Expr[i.M[N[T]]] = { import c.universe.{Apply=>ApplyTree,_} - + val util = ContextUtil[c.type](c) val mTC: Type = util.extractTC(i, InstanceTCName) val mttpe: Type = appliedType(mTC, nt.tpe :: Nil).normalize @@ -91,19 +91,24 @@ object Instance case Left(l) => (l.tree, nt.tpe.normalize) case Right(r) => (r.tree, mttpe) } + // the Symbol for the anonymous function passed to the appropriate Instance.map/flatMap/pure method + // this Symbol needs to be known up front so that it can be used as the owner of synthetic vals + val functionSym = util.functionSymbol(tree.pos) val instanceSym = util.singleton(i) - // A Tree that references the statically accessible Instance that provides the actual implementations of map, flatMap, ... + // A Tree that references the statically accessible Instance that provides the actual implementations of map, flatMap, ... val instance = Ident(instanceSym) val isWrapper: (String, Type, Tree) => Boolean = convert.asPredicate(c) + // Local definitions `defs` in the macro. This is used to ensure references are to M instances defined outside of the macro call. + // Also `refCount` is the number of references, which is used to create the private, synthetic method containing the body + val defs = util.collectDefs(tree, isWrapper) + val checkQual: Tree => Unit = util.checkReferences(defs, isWrapper) + type In = Input[c.universe.type] var inputs = List[In]() - // Local definitions in the macro. This is used to ensure references are to M instances defined outside of the macro call. - val defs = util.collectDefs(tree, isWrapper) - val checkQual: Tree => Unit = util.checkReferences(defs, isWrapper) // transforms the original tree into calls to the Instance functions pure, map, ..., // resulting in a value of type M[T] @@ -118,7 +123,8 @@ object Instance def pure(body: Tree): Tree = { val typeApplied = TypeApply(util.select(instance, PureName), TypeTree(treeType) :: Nil) - val p = ApplyTree(typeApplied, Function(Nil, body) :: Nil) + val f = util.createFunction(Nil, body, functionSym) + val p = ApplyTree(typeApplied, f :: Nil) if(t.isLeft) p else flatten(p) } // m should have type M[M[T]] @@ -133,9 +139,10 @@ object Instance def single(body: Tree, input: In): Tree = { val variable = input.local - val param = ValDef(util.parameterModifiers, variable.name, variable.tpt, EmptyTree) + val param = treeCopy.ValDef(variable, util.parameterModifiers, variable.name, variable.tpt, EmptyTree) val typeApplied = TypeApply(util.select(instance, MapName), variable.tpt :: TypeTree(treeType) :: Nil) - val mapped = ApplyTree(typeApplied, input.expr :: Function(param :: Nil, body) :: Nil) + val f = util.createFunction(param :: Nil, body, functionSym) + val mapped = ApplyTree(typeApplied, input.expr :: f :: Nil) if(t.isLeft) mapped else flatten(mapped) } @@ -145,37 +152,37 @@ object Instance val result = builder.make(c)(mTC, inputs) val param = util.freshMethodParameter( appliedType(result.representationC, util.idTC :: Nil) ) val bindings = result.extract(param) - val f = Function(param :: Nil, Block(bindings, body)) + val f = util.createFunction(param :: Nil, Block(bindings, body), functionSym) val ttt = TypeTree(treeType) val typedApp = TypeApply(util.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) } - // called when transforming the tree to add an input - // for `qual` of type M[A], and a selection qual.value, + // Called when transforming the tree to add an input. + // For `qual` of type M[A], and a `selection` qual.value, // the call is addType(Type A, Tree qual) - // the result is a Tree representing a reference to - // the bound value of the input - def addType(tpe: Type, qual: Tree): Tree = + // The result is a Tree representing a reference to + // the bound value of the input. + def addType(tpe: Type, qual: Tree, selection: Tree): Tree = { qual.foreach(checkQual) - val vd = util.freshValDef(tpe, qual.symbol) + val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) inputs ::= new Input(tpe, qual, vd) - util.refVal(vd, qual.pos) + util.refVal(selection, vd) } - def sub(name: String, tpe: Type, qual: Tree): Converted[c.type] = + def sub(name: String, tpe: Type, qual: Tree, replace: Tree): Converted[c.type] = { val tag = c.WeakTypeTag[T](tpe) convert[T](c)(name, qual)(tag) transform { tree => - addType(tpe, tree) + addType(tpe, tree, replace) } } // applies the transformation - val tx = util.transformWrappers(tree, (n,tpe,t) => sub(n,tpe,t)) + val tx = util.transformWrappers(tree, (n,tpe,t,replace) => sub(n,tpe,t,replace)) // resetting attributes must be: a) local b) done here and not wider or else there are obscure errors - val tr = makeApp( c.resetLocalAttrs( inner(tx) ) ) + val tr = makeApp( inner(tx) ) c.Expr[i.M[N[T]]](tr) } diff --git a/util/appmacro/src/main/scala/sbt/appmacro/KListBuilder.scala b/util/appmacro/src/main/scala/sbt/appmacro/KListBuilder.scala index c22825c1b..e9fb207d8 100644 --- a/util/appmacro/src/main/scala/sbt/appmacro/KListBuilder.scala +++ b/util/appmacro/src/main/scala/sbt/appmacro/KListBuilder.scala @@ -33,8 +33,10 @@ object KListBuilder extends TupleBuilder def bindKList(prev: ValDef, revBindings: List[ValDef], params: List[ValDef]): List[ValDef] = params match { - case ValDef(mods, name, tpt, _) :: xs => - val head = ValDef(mods, name, tpt, select(Ident(prev.name), "head")) + case (x @ ValDef(mods, name, tpt, _)) :: xs => + val rhs = select(Ident(prev.name), "head") + val head = treeCopy.ValDef(x, mods, name, tpt, rhs) + util.setSymbol(head, x.symbol) val tail = localValDef(TypeTree(), select(Ident(prev.name), "tail")) val base = head :: revBindings bindKList(tail, if(xs.isEmpty) base else tail :: base, xs) @@ -53,7 +55,7 @@ object KListBuilder extends TupleBuilder val klist = makeKList(inputs.reverse, knil, knilType) /** The input types combined in a KList type. The main concern is tracking the heterogeneous types. - * The type constructor is tcVariable, so that it can be applied to [X] X or M later. + * The type constructor is tcVariable, so that it can be applied to [X] X or M later. * When applied to `M`, this type gives the type of the `input` KList. */ val klistType: Type = (inputs :\ knilType)( (in, klist) => kconsType(in.tpe, klist) ) diff --git a/util/appmacro/src/main/scala/sbt/appmacro/TupleNBuilder.scala b/util/appmacro/src/main/scala/sbt/appmacro/TupleNBuilder.scala index 805098353..89fe31792 100644 --- a/util/appmacro/src/main/scala/sbt/appmacro/TupleNBuilder.scala +++ b/util/appmacro/src/main/scala/sbt/appmacro/TupleNBuilder.scala @@ -42,9 +42,11 @@ object TupleNBuilder extends TupleBuilder def bindTuple(param: ValDef, revBindings: List[ValDef], params: List[ValDef], i: Int): List[ValDef] = params match { - case ValDef(mods, name, tpt, _) :: xs => - val x = ValDef(mods, name, tpt, select(Ident(param.name), "_" + i.toString)) - bindTuple(param, x :: revBindings, xs, i+1) + case (x @ ValDef(mods, name, tpt, _)) :: xs => + val rhs = select(Ident(param.name), "_" + i.toString) + val newVal = treeCopy.ValDef(x, mods, name, tpt, rhs) + util.setSymbol(newVal, x.symbol) + bindTuple(param, newVal :: revBindings, xs, i+1) case Nil => revBindings.reverse } }