From 076480b50af6f63ae0105c088efd169a2ab87290 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 28 Jan 2013 17:14:53 -0500 Subject: [PATCH] Reduce InputTask to the ideal wrapper around 'State => Parser[Initialize[Task[T]]]' Ref #407. --- .../src/main/scala/sbt/InputTask.scala | 161 +++++++++--------- .../src/main/scala/sbt/std/TaskMacro.scala | 61 ++++--- main/src/main/scala/sbt/Aggregation.scala | 14 +- .../main/scala/sbt/test/ScriptedTests.scala | 2 +- .../standard/src/main/scala/sbt/Action.scala | 29 +++- .../src/main/scala/sbt/std/TaskExtra.scala | 28 ++- .../main/scala/sbt/appmacro/ContextUtil.scala | 7 + 7 files changed, 165 insertions(+), 137 deletions(-) diff --git a/main/settings/src/main/scala/sbt/InputTask.scala b/main/settings/src/main/scala/sbt/InputTask.scala index 06c958916..101a90983 100644 --- a/main/settings/src/main/scala/sbt/InputTask.scala +++ b/main/settings/src/main/scala/sbt/InputTask.scala @@ -7,112 +7,115 @@ package sbt import Types._ /** Parses input and produces a task to run. Constructed using the companion object. */ -sealed trait InputTask[T] -{ outer => - private[sbt] type Result - private[sbt] def parser: State => Parser[Result] - private[sbt] def defined: AttributeKey[Result] - private[sbt] def task: Task[T] - - def mapTask[S](f: Task[T] => Task[S]) = new InputTask[S] { - type Result = outer.Result - def parser = outer.parser - def task = f(outer.task) - def defined = outer.defined - } +final class InputTask[T] private(val parser: State => Parser[Task[T]]) +{ + def mapTask[S](f: Task[T] => Task[S]): InputTask[S] = + new InputTask[S](s => parser(s) map f) } object InputTask { - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") + def make[T](p: State => Parser[Task[T]]): InputTask[T] = new InputTask[T](p) + def static[T](p: Parser[Task[T]]): InputTask[T] = free(_ => p) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") def static[I,T](p: Parser[I])(c: I => Task[T]): InputTask[T] = static(p map c) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") - def free[T](p: State => Parser[Task[T]]): InputTask[T] = { - val key = localKey[Task[T]] - new InputTask[T] { - type Result = Task[T] - def parser = p - def defined = key - def task = getResult(key) - } - } + def free[T](p: State => Parser[Task[T]]): InputTask[T] = make(p) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") def free[I,T](p: State => Parser[I])(c: I => Task[T]): InputTask[T] = free(s => p(s) map c) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") def separate[I,T](p: State => Parser[I])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = separate(Def value p)(action) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") def separate[I,T](p: Initialize[State => Parser[I]])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = p.zipWith(action)((parser, act) => free(parser)(act)) - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") - def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = + /** Constructs an InputTask that accepts no user input. */ + def createFree[T](action: Initialize[Task[T]]): Initialize[InputTask[T]] = + action { tsk => free(emptyParser)( const(tsk) ) } + + /** Constructs an InputTask from: + * a) a Parser constructed using other Settings, but not Tasks + * b) an action constructed using Settings, Tasks, and the result of parsing */ + def create[I,T](p: Initialize[State => Parser[I]])(action: Initialize[Task[I => T]]): Initialize[InputTask[T]] = { - create(p){ it => - val dummy = TaskKey(localKey[Task[I]]) - action(dummy) mapConstant subResultForDummy(dummy) - } + val act = action { (tf: Task[I => T]) => (i: I) => tf.map(f => f(i)) } + separate(p)(act) } - @deprecated("Use `create` or the `Def.inputTask` macro.", "0.13.0") - def apply[I,T](p: State => Parser[I])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = - apply(Def.value(p))(action) - - // dummy task that will get replaced with the actual mappings from InputTasks to parse results - private[sbt] lazy val inputMap: Task[AttributeMap] = mktask { error("Internal sbt error: input map not substituted.") } - private[this] def getResult[T](key: AttributeKey[Task[T]]): Task[T] = inputMap flatMap { im => - im get key getOrElse error("Internal sbt error: could not get parser result.") - } - /** The proper solution is to have a Manifest context bound and accept slight source incompatibility, - * The affected InputTask construction methods are all deprecated and so it is better to keep complete - * compatibility. Because the AttributeKey is local, it uses object equality and the manifest is not used. */ - private[this] def localKey[T]: AttributeKey[T] = AttributeKey.local[Unit].asInstanceOf[AttributeKey[T]] - - private[this] def subResultForDummy[I](dummy: TaskKey[I]) = - new (ScopedKey ~> Option) { def apply[T](sk: ScopedKey[T]) = - if(sk.key eq dummy.key) { - // sk.key: AttributeKey[T], dummy.key: AttributeKey[Task[I]] - // (sk.key eq dummy.key) ==> T == Task[I] because AttributeKey is invariant - Some(getResult(dummy.key).asInstanceOf[T]) - } else - None - } - - // This interface allows the Parser to be constructed using other Settings, but not Tasks (which is desired). - // The action can be constructed using Settings and Tasks and with the parse result injected into a Task. - // This requires Aggregation.applyDynamicTasks to inject an AttributeMap with the parse results. - def create[I,T](p: Initialize[State => Parser[I]])(action: Initialize[Task[I]] => Initialize[Task[T]]): Initialize[InputTask[T]] = - { - val key = localKey[I] // TODO: AttributeKey.local[I] - val result: Initialize[Task[I]] = (Def.resolvedScoped zipWith Def.valueStrict(InputTask.inputMap)){(scoped, imTask) => - imTask map { im => im get key getOrElse error("No parsed value for " + Def.displayFull(scoped) + "\n" + im) } - } - - (p zipWith action(result)) { (parserF, act) => - new InputTask[T] - { - type Result = I - def parser = parserF - def task = act - def defined = key - } - } - } + /** Constructs an InputTask from: + * a) a Parser constructed using other Settings, but not Tasks + * b) a dynamically constructed Task that uses Settings, Tasks, and the result of parsing. */ + def createDyn[I,T](p: Initialize[State => Parser[I]])(action: Initialize[Task[I => Initialize[Task[T]]]]): Initialize[InputTask[T]] = + separate(p)(std.FullInstance.flattenFun[I,T](action)) /** A dummy parser that consumes no input and produces nothing useful (unit).*/ - def emptyParser: Initialize[State => Parser[Unit]] = parserAsInput(complete.DefaultParsers.success(())) + def emptyParser: State => Parser[Unit] = Types.const(complete.DefaultParsers.success(())) /** Implementation detail that is public because it is used by a macro.*/ def parserAsInput[T](p: Parser[T]): Initialize[State => Parser[T]] = Def.valueStrict(Types.const(p)) /** Implementation detail that is public because it is used y a macro.*/ def initParserAsInput[T](i: Initialize[Parser[T]]): Initialize[State => Parser[T]] = i(Types.const) + + + + @deprecated("Use another InputTask constructor or the `Def.inputTask` macro.", "0.13.0") + def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = + { + val dummyKey = localKey[Task[I]] + val (marker, dummy) = dummyTask[I] + val it = action(TaskKey(dummyKey)) mapConstant subResultForDummy(dummyKey, dummy) + val act = it { tsk => (value: I) => subForDummy(marker, value, tsk) } + separate(p)(act) + } + + @deprecated("Use another InputTask constructor or the `Def.inputTask` macro.", "0.13.0") + def apply[I,T](p: State => Parser[I])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = + apply(Def.value(p))(action) + + /** The proper solution is to have a Manifest context bound and accept slight source incompatibility, + * The affected InputTask construction methods are all deprecated and so it is better to keep complete + * compatibility. Because the AttributeKey is local, it uses object equality and the manifest is not used. */ + private[this] def localKey[T]: AttributeKey[T] = AttributeKey.local[Unit].asInstanceOf[AttributeKey[T]] + + private[this] def subResultForDummy[I](dummyKey: AttributeKey[Task[I]], dummyTask: Task[I]) = + new (ScopedKey ~> Option) { def apply[T](sk: ScopedKey[T]) = + if(sk.key eq dummyKey) { + // sk.key: AttributeKey[T], dummy.key: AttributeKey[Task[I]] + // (sk.key eq dummy.key) ==> T == Task[I] because AttributeKey is invariant + Some(dummyTask.asInstanceOf[T]) + } else + None + } + + private[this] def dummyTask[I]: (AttributeKey[Option[I]], Task[I]) = + { + val key = localKey[Option[I]] + val f: () => I = () => error(s"Internal sbt error: InputTask stub was not substituted properly.") + val t: Task[I] = Task(Info[I]().set(key, None), Pure(f, false)) + (key, t) + } + private[this] def subForDummy[I, T](marker: AttributeKey[Option[I]], value: I, task: Task[T]): Task[T] = + { + val seen = new java.util.IdentityHashMap[Task[_], Task[_]] + lazy val f: Task ~> Task = new (Task ~> Task) { def apply[T](t: Task[T]): Task[T] = + { + val t0 = seen.get(t) + if(t0 == null) { + val newAction = + if(t.info.get(marker).isDefined) + Pure(() => value.asInstanceOf[T], inline = true) + else + t.work.mapTask(f) + val newTask = Task(t.info, newAction) + seen.put(t, newTask) + newTask + } else + t0.asInstanceOf[Task[T]] + }} + f(task) + } } diff --git a/main/settings/src/main/scala/sbt/std/TaskMacro.scala b/main/settings/src/main/scala/sbt/std/TaskMacro.scala index fb858467b..1b68c4316 100644 --- a/main/settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main/settings/src/main/scala/sbt/std/TaskMacro.scala @@ -17,7 +17,7 @@ object TaskInstance extends MonadInstance import TaskExtra._ final type M[x] = Task[x] - def app[K[L[x]], Z](in: K[Task], f: K[Id] => Z)(implicit a: AList[K]): Task[Z] = new Mapped[Z,K](in, f compose allM, a) + def app[K[L[x]], Z](in: K[Task], f: K[Id] => Z)(implicit a: AList[K]): Task[Z] = Task(Info(), new Mapped[Z,K](in, f compose allM, a)) def map[S,T](in: Task[S], f: S => T): Task[T] = in map f def flatten[T](in: Task[Task[T]]): Task[T] = in flatMap idFun[Task[T]] def pure[T](t: () => T): Task[T] = toTask(t) @@ -38,6 +38,15 @@ object FullInstance extends Instance.Composed[Initialize, Task](InitializeInstan (a, data) flatMap { case (a,d) => f(a) evaluate d } } } + def flattenFun[S,T](in: Initialize[Task[ S => Initialize[Task[T]] ]]): Initialize[S => Task[T]] = + { + import Scoped._ + (in,settingsData, Def.capturedTransformations) apply{ + (a: Task[S => Initialize[Task[T]]], data: Task[SS], f) => (s: S) => + import TaskExtra.multT2Task + (a, data) flatMap { case (af,d) => f(af(s)) evaluate d } + } + } } /** Converts an input `Tree` of type `Initialize[T]`, `Initialize[Task[T]]`, or `Task[T]` into a `Tree` of type `Initialize[Task[T]]`.*/ object FullConvert extends Convert @@ -69,6 +78,8 @@ object TaskMacro final val AppendNInitName = "appendN" final val TransformInitName = "transform" final val InputTaskCreateName = "create" + final val InputTaskCreateDynName = "createDyn" + final val InputTaskCreateFreeName = "createFree" def taskMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Initialize[Task[T]]] = Instance.contImpl[T](c, FullInstance, FullConvert, MixedBuilder)(Left(t)) @@ -272,9 +283,6 @@ object TaskMacro val ttree = t match { case Left(l) => l.tree; case Right(r) => r.tree } val defs = util.collectDefs(ttree, isAnyWrapper) val checkQual = util.checkReferences(defs, isAnyWrapper) - val unitInitTask = c.typeOf[Initialize[Task[Unit]]] - val initKeyC = c.typeOf[Initialize[Unit]].typeConstructor - val taskKeyC = c.typeOf[Task[Unit]].typeConstructor var result: Option[(Tree, Type, ValDef)] = None @@ -287,42 +295,47 @@ object TaskMacro else { qual.foreach(checkQual) - val itType = appliedType(initKeyC, appliedType(taskKeyC, tpe :: Nil) :: Nil) // Initialize[Task[]] - val vd = util.freshValDef(itType, qual.symbol) // val $x: Initialize[Task[]] + val vd = util.freshValDef(tpe, qual.symbol) // val $x: result = Some( (qual, tpe, vd) ) val tree = util.refVal(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) - val wrapped = InputWrapper.wrapKey(c)( c.Expr[Any](tree) )( c.WeakTypeTag(tpe) ) - wrapped.tree.setType(tpe) + tree.setType(tpe) + tree } - // Tree for InputTask.create[, ](arg1)(arg2) - def inputTaskCreate(tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = + // Tree for InputTask.[, ](arg1)(arg2) + def inputTaskCreate(name: String, tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = { - val typedApp = TypeApply(Select(it, InputTaskCreateName), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil) + val typedApp = TypeApply(Select(it, name), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil) val app = ApplyTree( ApplyTree(typedApp, arg1 :: Nil), arg2 :: Nil) c.Expr[Initialize[InputTask[T]]](app) } - def expandTask(dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[T]]] = + // Tree for InputTask.createFree[](arg1) + def inputTaskCreateFree(tpe: Type, arg: Tree) = + { + val typedApp = TypeApply(Select(it, InputTaskCreateFreeName), TypeTree(tpe) :: Nil) + val app = ApplyTree(typedApp, arg :: Nil) + c.Expr[Initialize[InputTask[T]]](app) + } + def expandTask[I: WeakTypeTag](dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[I]]] = if(dyn) - taskDynMacroImpl[T](c)( c.Expr[Initialize[Task[T]]](tx) ) + taskDynMacroImpl[I](c)( c.Expr[Initialize[Task[I]]](tx) ) else - taskMacroImpl[T](c)( c.Expr[T](tx) ) + taskMacroImpl[I](c)( c.Expr[I](tx) ) + def wrapTag[I: WeakTypeTag]: WeakTypeTag[Initialize[Task[I]]] = weakTypeTag val tx = util.transformWrappers(ttree, isParserWrapper, (tpe,tree) => subWrapper(tpe,tree)) - val body = c.resetLocalAttrs( expandTask(t.isRight, tx).tree ) result match { case Some((p, tpe, param)) => - val f = Function(param :: Nil, body) - inputTaskCreate(tpe, tag.tpe, p, f) + val fCore = Function(param :: Nil, tx) + val bodyTpe = if(t.isRight) wrapTag(tag).tpe else 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 ) + inputTaskCreate(if(t.isRight) InputTaskCreateDynName else InputTaskCreateName, tpe, tag.tpe, p, fInit) case None => - // SI-6591 prevents the more direct version using reify: - // reify { InputTask[Unit,T].create(TaskMacro.emptyParser)(Types.const(body.splice)) } - val initType = c.weakTypeOf[Initialize[Task[T]]] - val tt = Ident(util.singleton(Types)) - val f = ApplyTree(TypeApply(Select(tt, "const"), TypeTree(unitInitTask) :: TypeTree(initType) :: Nil), body :: Nil) - val p = reify { InputTask.emptyParser } - inputTaskCreate(c.typeOf[Unit], tag.tpe, p.tree, f) + val init = c.resetLocalAttrs( expandTask[T](t.isRight, tx).tree ) + inputTaskCreateFree(tag.tpe, init) } } } diff --git a/main/src/main/scala/sbt/Aggregation.scala b/main/src/main/scala/sbt/Aggregation.scala index 052b72186..26d206bd0 100644 --- a/main/src/main/scala/sbt/Aggregation.scala +++ b/main/src/main/scala/sbt/Aggregation.scala @@ -95,18 +95,10 @@ final object Aggregation def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputTask[I]], show: Boolean)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = { - final class Parsed[T](val input: InputTask[_] { type Result = T }, val value: T) { - def addTo(im: AttributeMap): AttributeMap = im.put(input.defined, value) - } - val parsers: Seq[Parser[Parsed[_]]] = for( KeyValue(k,t) <- inputs ) yield - t.parser(s).map( v => new Parsed[t.Result](t, v) ) - - Command.applyEffect(seq(parsers)) { parseds => + val parsers = for(KeyValue(k,it) <- inputs) yield it.parser(s).map(v => KeyValue(k,v)) + Command.applyEffect(seq(parsers)) { roots => import EvaluateTask._ - val inputMap = (AttributeMap.empty /: parseds) { (im, p) => p.addTo(im) } - val dummies = DummyTaskMap(new TaskAndValue(InputTask.inputMap, inputMap) :: Nil) - val roots = maps(inputs)(_.task) - runTasks(s, structure, roots, dummies, show) + runTasks(s, structure, roots, DummyTaskMap(Nil), show) } } diff --git a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala index 56b43bcde..ae93ed836 100644 --- a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala +++ b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala @@ -119,7 +119,7 @@ object ScriptedTests } def runAll(tests: Seq[() => Option[String]]) { - val errors = for(test <- tests; err <- test()) yield err + val errors = for(test <- tests.par; err <- test()) yield err if(errors.nonEmpty) error(errors.mkString("Failed tests:\n\t", "\n\t", "\n")) } diff --git a/tasks/standard/src/main/scala/sbt/Action.scala b/tasks/standard/src/main/scala/sbt/Action.scala index 5cec0b46b..368b8f46b 100644 --- a/tasks/standard/src/main/scala/sbt/Action.scala +++ b/tasks/standard/src/main/scala/sbt/Action.scala @@ -11,25 +11,39 @@ package sbt // Various natural transformations used, such as PMap, require invariant type constructors for correctness /** Defines a task compuation*/ -sealed trait Action[T] +sealed trait Action[T] { + // TODO: remove after deprecated InputTask constructors are removed + private[sbt] def mapTask(f: Task ~> Task): Action[T] +} + /** A direct computation of a value. * If `inline` is true, `f` will be evaluated on the scheduler thread without the overhead of normal scheduling when possible. -* This is intended as an optimization for already evaluated values or very short computations. */ -final case class Pure[T](f: () => T, inline: Boolean) extends Action[T] +* This is intended as an optimization for already evaluated values or very short pure computations. */ +final case class Pure[T](f: () => T, inline: Boolean) extends Action[T] { + private[sbt] def mapTask(f: Task ~> Task) = this +} /** Applies a function to the result of evaluating a heterogeneous list of other tasks.*/ -final case class Mapped[T, K[L[x]]](in: K[Task], f: K[Result] => T, alist: AList[K]) extends Action[T] +final case class Mapped[T, K[L[x]]](in: K[Task], f: K[Result] => T, alist: AList[K]) extends Action[T] { + private[sbt] def mapTask(g: Task ~> Task) = Mapped[T,K](alist.transform(in, g), f, alist) +} /** Computes another task to evaluate based on results from evaluating other tasks.*/ -final case class FlatMapped[T, K[L[x]]](in: K[Task], f: K[Result] => Task[T], alist: AList[K]) extends Action[T] +final case class FlatMapped[T, K[L[x]]](in: K[Task], f: K[Result] => Task[T], alist: AList[K]) extends Action[T] { + private[sbt] def mapTask(g: Task ~> Task) = FlatMapped[T,K](alist.transform(in, g), g.fn[T] compose f, alist) +} /** A computation `in` that requires other tasks `deps` to be evaluated first.*/ -final case class DependsOn[T](in: Task[T], deps: Seq[Task[_]]) extends Action[T] +final case class DependsOn[T](in: Task[T], deps: Seq[Task[_]]) extends Action[T] { + private[sbt] def mapTask(g: Task ~> Task) = DependsOn[T](g(in), deps.map(t => g(t))) +} /** A computation that operates on the results of a homogeneous list of other tasks. * It can either return another task to be evaluated or the final value.*/ -final case class Join[T, U](in: Seq[Task[U]], f: Seq[Result[U]] => Either[Task[T], T]) extends Action[T] +final case class Join[T, U](in: Seq[Task[U]], f: Seq[Result[U]] => Either[Task[T], T]) extends Action[T] { + private[sbt] def mapTask(g: Task ~> Task) = Join[T,U](in.map(g.fn[U]), sr => f(sr).left.map(g.fn[T])) +} /** Combines metadata `info` and a computation `work` to define a task. */ final case class Task[T](info: Info[T], work: Action[T]) @@ -37,6 +51,7 @@ final case class Task[T](info: Info[T], work: Action[T]) override def toString = info.name getOrElse ("Task(" + info + ")") override def hashCode = info.hashCode + private[sbt] def mapTask(g: Task ~> Task): Task[T] = g(Task(info, work.mapTask(g))) def tag(tags: Tag*): Task[T] = tagw(tags.map(t => (t, 1)) : _*) def tagw(tags: (Tag, Int)*): Task[T] = copy(info = info.set(tagsKey, info.get(tagsKey).getOrElse(Map.empty) ++ tags )) def tags: TagMap = info get tagsKey getOrElse Map.empty diff --git a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala index ef844d9de..e216065ff 100644 --- a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala @@ -89,11 +89,9 @@ trait TaskExtra final def nop: Task[Unit] = constant( () ) final def constant[T](t: T): Task[T] = task(t) - final implicit def actionToTask[T](a: Action[T]): Task[T] = Task(Info(), a) - final def task[T](f: => T): Task[T] = toTask(f _) - final implicit def toTask[T](f: () => T): Task[T] = new Pure(f, false) - final def inlineTask[T](value: T): Task[T] = new Pure(() => value, true) + final implicit def toTask[T](f: () => T): Task[T] = Task(Info(), new Pure(f, false)) + final def inlineTask[T](value: T): Task[T] = Task(Info(), new Pure(() => value, true)) final implicit def upcastTask[A >: B, B](t: Task[B]): Task[A] = t map { x => x : A } final implicit def toTasks[S](in: Seq[() => S]): Seq[Task[S]] = in.map(toTask) @@ -106,20 +104,20 @@ trait TaskExtra final implicit def joinAnyTasks(in: Seq[Task[_]]): JoinTask[Any, Seq] = joinTasks[Any]( existToAny(in) ) final implicit def joinTasks[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] { - def join: Task[Seq[S]] = new Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s)) ) + def join: Task[Seq[S]] = Task[Seq[S]](Info(), new Join(in, (s: Seq[Result[S]]) => Right(TaskExtra.all(s)) )) def reduced(f: (S,S) => S): Task[S] = TaskExtra.reduced(in.toIndexedSeq, f) } final implicit def multT2Task[A,B](in: (Task[A], Task[B])) = multInputTask[({ type l[L[x]] = (L[A], L[B]) })#l](in)(AList.tuple2[A,B]) final implicit def multInputTask[K[L[X]]](tasks: K[Task])(implicit a: AList[K]): MultiInTask[K] = new MultiInTask[K] { - def flatMapR[T](f: K[Result] => Task[T]): Task[T] = new FlatMapped[T,K](tasks, f, a) - def flatMap[T](f: K[Id] => Task[T]): Task[T] = new FlatMapped[T, K](tasks, f compose allM, a) - def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = new FlatMapped[T,K](tasks, f compose anyFailM, a) + def flatMapR[T](f: K[Result] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T,K](tasks, f, a)) + def flatMap[T](f: K[Id] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T, K](tasks, f compose allM, a)) + def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T,K](tasks, f compose anyFailM, a)) - def mapR[T](f: K[Result] => T): Task[T] = new Mapped[T,K](tasks, f, a) - def map[T](f: K[Id] => T): Task[T] = new Mapped[T,K](tasks, f compose allM, a) - def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = new Mapped[T,K](tasks, f compose anyFailM, a) + def mapR[T](f: K[Result] => T): Task[T] = Task(Info(), new Mapped[T,K](tasks, f, a)) + def map[T](f: K[Id] => T): Task[T] = Task(Info(), new Mapped[T,K](tasks, f compose allM, a)) + def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = Task(Info(), new Mapped[T,K](tasks, f compose anyFailM, a)) } final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] { @@ -129,9 +127,9 @@ trait TaskExtra def failure: Task[Incomplete] = mapFailure(idFun) def result: Task[Result[S]] = mapR(idFun) - def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, K](in, f, ml) - def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, K](in, f, ml) - def dependsOn(tasks: Task[_]*): Task[S] = new DependsOn(in, tasks) + def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T, K](in, f, ml)) + def mapR[T](f: Result[S] => T): Task[T] = Task(Info(), new Mapped[T, K](in, f, ml)) + def dependsOn(tasks: Task[_]*): Task[S] = Task(Info(), new DependsOn(in, tasks)) def flatMap[T](f: S => Task[T]): Task[T] = flatMapR(f compose successM) def flatFailure[T](f: Incomplete => Task[T]): Task[T] = flatMapR(f compose failM) @@ -230,7 +228,7 @@ object TaskExtra extends TaskExtra } def failuresM[K[L[x]]](implicit a: AList[K]): K[Result] => Seq[Incomplete] = x => failures[Any](a.toList(x)) - def all[D](in: Seq[Result[D]]) = + def all[D](in: Seq[Result[D]]): Seq[D] = { val incs = failures(in) if(incs.isEmpty) in.map(Result.tryValue.fn[D]) else throw incompleteDeps(incs) diff --git a/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala b/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala index a62846e78..3afc0d617 100644 --- a/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala +++ b/util/appmacro/src/main/scala/sbt/appmacro/ContextUtil.scala @@ -143,6 +143,13 @@ final class ContextUtil[C <: Context](val ctx: C) /** >: Nothing <: Any */ def emptyTypeBounds: TypeBounds = TypeBounds(definitions.NothingClass.toType, definitions.AnyClass.toType) + 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): Tree = {