From 51f7d2e24ac46fa297efa7344e8f511a0900b4bd Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 22 Jan 2017 22:51:01 -0500 Subject: [PATCH] Adds an Append instance that extracts taskValue This adds a macro-level hack to support += op for sourceGenerators and resourceGenerators using RHS of Initialize[Task[Seq[File]]]. When the types match up, the macro now calls `.taskValue` automatically. --- main-settings/src/main/scala/sbt/Append.scala | 10 ++++++++ .../src/main/scala/sbt/std/TaskMacro.scala | 25 ++++++++++++++----- main/src/main/scala/sbt/Defaults.scala | 2 +- sbt/src/sbt-test/actions/generator/build.sbt | 13 ++++++++++ sbt/src/sbt-test/actions/generator/test | 2 ++ .../build.sbt | 4 +-- .../project/TestP.scala | 4 +-- 7 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 sbt/src/sbt-test/actions/generator/build.sbt create mode 100644 sbt/src/sbt-test/actions/generator/test diff --git a/main-settings/src/main/scala/sbt/Append.scala b/main-settings/src/main/scala/sbt/Append.scala index b44ce8090..24b9447f1 100644 --- a/main-settings/src/main/scala/sbt/Append.scala +++ b/main-settings/src/main/scala/sbt/Append.scala @@ -4,6 +4,8 @@ import java.io.File import Def.Classpath import scala.annotation.implicitNotFound import sbt.internal.util.Attributed +import Def.Initialize +import reflect.internal.annotations.compileTimeOnly object Append { @implicitNotFound(msg = "No implicit for Append.Value[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}") @@ -24,6 +26,14 @@ object Append { def appendValues(a: Seq[T], b: Seq[V]): Seq[T] = a ++ (b map { x => (x: T) }) def appendValue(a: Seq[T], b: V): Seq[T] = a :+ (b: T) } + @compileTimeOnly("This can be used in += only.") + implicit def appendTaskValueSeq[T, V <: T]: Value[Seq[Task[T]], Initialize[Task[V]]] = new Value[Seq[Task[T]], Initialize[Task[V]]] { + def appendValue(a: Seq[Task[T]], b: Initialize[Task[V]]): Seq[Task[T]] = ??? + } + @compileTimeOnly("This can be used in += only.") + implicit def appendTaskKeySeq[T, V <: T]: Value[Seq[Task[T]], TaskKey[V]] = new Value[Seq[Task[T]], TaskKey[V]] { + def appendValue(a: Seq[Task[T]], b: TaskKey[V]): Seq[Task[T]] = ??? + } implicit def appendList[T, V <: T]: Sequence[List[T], List[V], V] = new Sequence[List[T], List[V], V] { def appendValues(a: List[T], b: List[V]): List[T] = a ::: b def appendValue(a: List[T], b: V): List[T] = a :+ b diff --git a/main-settings/src/main/scala/sbt/std/TaskMacro.scala b/main-settings/src/main/scala/sbt/std/TaskMacro.scala index c12900150..42aca5cde 100644 --- a/main-settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main-settings/src/main/scala/sbt/std/TaskMacro.scala @@ -161,9 +161,23 @@ object TaskMacro { /** Implementation of += macro for settings. */ def settingAppend1Impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(v: c.Expr[U])(a: c.Expr[Append.Value[T, U]]): c.Expr[Setting[T]] = { - val init = SettingMacro.settingMacroImpl[U](c)(v) - val append = appendMacroImpl(c)(init.tree, a.tree)(Append1InitName) - c.Expr[Setting[T]](append) + import c.universe._ + val ttpe = c.weakTypeOf[T] + val typeArgs = ttpe.typeArgs + v.tree.tpe match { + // To allow Initialize[Task[A]] in the position of += RHS, we're going to call "taskValue" automatically. + case tpe if typeArgs.nonEmpty && (tpe weak_<:< c.weakTypeOf[Initialize[_]]) => + c.macroApplication match { + case Apply(Apply(TypeApply(Select(preT, nmeT), targs), _), _) => + val tree = Apply(TypeApply(Select(preT, TermName("+=").encodedName), TypeTree(typeArgs.head) :: Nil), Select(v.tree, TermName("taskValue").encodedName) :: Nil) + c.Expr[Setting[T]](tree) + case x => ContextUtil.unexpectedTree(x) + } + case _ => + val init = SettingMacro.settingMacroImpl[U](c)(v) + val append = appendMacroImpl(c)(init.tree, a.tree)(Append1InitName) + c.Expr[Setting[T]](append) + } } /** Implementation of ++= macro for tasks. */ def taskAppendNImpl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(vs: c.Expr[U])(a: c.Expr[Append.Values[T, U]]): c.Expr[Setting[Task[T]]] = @@ -179,7 +193,6 @@ object TaskMacro { val append = appendMacroImpl(c)(init.tree, a.tree)(AppendNInitName) c.Expr[Setting[T]](append) } - /** Implementation of -= macro for tasks. */ def taskRemove1Impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: blackbox.Context)(v: c.Expr[U])(r: c.Expr[Remove.Value[T, U]]): c.Expr[Setting[Task[T]]] = { @@ -213,8 +226,8 @@ object TaskMacro { { import c.universe._ c.macroApplication match { - case Apply(Apply(TypeApply(Select(preT, nmeT), targs), _), a) => - Apply(Apply(TypeApply(Select(preT, TermName(newName).encodedName), targs), init :: sourcePosition(c).tree :: Nil), a) + case Apply(Apply(TypeApply(Select(preT, nmeT), targs), _), _) => + Apply(Apply(TypeApply(Select(preT, TermName(newName).encodedName), targs), init :: sourcePosition(c).tree :: Nil), append :: Nil) case x => ContextUtil.unexpectedTree(x) } } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index c6b98d0d9..94e0a5e82 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -261,7 +261,7 @@ object Defaults extends BuildCommon { unmanagedResources := collectFiles(unmanagedResourceDirectories, includeFilter in unmanagedResources, excludeFilter in unmanagedResources).value, watchSources in ConfigGlobal ++= unmanagedResources.value, resourceGenerators :== Nil, - resourceGenerators += (Def.task { PluginDiscovery.writeDescriptors(discoveredSbtPlugins.value, resourceManaged.value) }).taskValue, + resourceGenerators += Def.task { PluginDiscovery.writeDescriptors(discoveredSbtPlugins.value, resourceManaged.value) }, managedResources := generate(resourceGenerators).value, resources := Classpaths.concat(managedResources, unmanagedResources).value ) diff --git a/sbt/src/sbt-test/actions/generator/build.sbt b/sbt/src/sbt-test/actions/generator/build.sbt new file mode 100644 index 000000000..c347b414e --- /dev/null +++ b/sbt/src/sbt-test/actions/generator/build.sbt @@ -0,0 +1,13 @@ +lazy val buildInfo = taskKey[Seq[File]]("The task that generates the build info.") + +lazy val root = (project in file(".")) + .settings( + scalaVersion := "2.11.8", + buildInfo := { + val x = sourceManaged.value / "BuildInfo.scala" + IO.write(x, """object BuildInfo""") + x :: Nil + }, + sourceGenerators in Compile += buildInfo, + sourceGenerators in Compile += Def.task { Nil } + ) diff --git a/sbt/src/sbt-test/actions/generator/test b/sbt/src/sbt-test/actions/generator/test new file mode 100644 index 000000000..385612f46 --- /dev/null +++ b/sbt/src/sbt-test/actions/generator/test @@ -0,0 +1,2 @@ +> compile +$ exists target/scala-2.11/src_managed/BuildInfo.scala diff --git a/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/build.sbt b/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/build.sbt index 601ed7611..bea5471fd 100644 --- a/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/build.sbt +++ b/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/build.sbt @@ -1,8 +1,8 @@ val test123 = project in file(".") enablePlugins TestP settings( - resourceGenerators in Compile += (Def.task { + resourceGenerators in Compile += Def.task { streams.value.log info "resource generated in settings" Nil - }).taskValue + } ) TaskKey[Unit]("check") := { diff --git a/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/project/TestP.scala b/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/project/TestP.scala index ce7b6f707..e54d62d71 100644 --- a/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/project/TestP.scala +++ b/sbt/src/sbt-test/project/auto-plugins-default-requires-jvmplugin/project/TestP.scala @@ -2,9 +2,9 @@ import sbt._, syntax._, Keys._ object TestP extends AutoPlugin { override def projectSettings: Seq[Setting[_]] = Seq( - resourceGenerators in Compile += (Def.task { + resourceGenerators in Compile += Def.task { streams.value.log info "resource generated in plugin" Nil - }).taskValue + } ) }