diff --git a/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala b/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala index 9c5b1bf0c..c082c1079 100644 --- a/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala +++ b/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala @@ -93,4 +93,20 @@ trait ContextUtil[C <: Quotes & scala.Singleton](val qctx: C): case _ => super.transformTerm(tree)(owner) end refTransformer refTransformer.transformTerm(tree)(Symbol.spliceOwner) + + def collectDefs(tree: Term, isWrapper: (String, TypeRepr, Term) => Boolean): Set[Symbol] = + val defs = mutable.HashSet[Symbol]() + object traverser extends TreeTraverser: + override def traverseTree(tree: Tree)(owner: Symbol): Unit = + tree match + case Ident(_) => () + case Apply(TypeApply(Select(_, nme), tpe :: Nil), qual :: Nil) + if isWrapper(nme, tpe.tpe, qual) => + () + case _ => + if tree.symbol ne null then defs += tree.symbol + super.traverseTree(tree)(owner) + end traverser + traverser.traverseTree(tree)(Symbol.spliceOwner) + defs.toSet end ContextUtil diff --git a/core-macros/src/main/scala/sbt/internal/util/appmacro/Convert.scala b/core-macros/src/main/scala/sbt/internal/util/appmacro/Convert.scala index 14b42d7e4..1ba9aa51b 100644 --- a/core-macros/src/main/scala/sbt/internal/util/appmacro/Convert.scala +++ b/core-macros/src/main/scala/sbt/internal/util/appmacro/Convert.scala @@ -23,10 +23,11 @@ trait Convert[C <: Quotes & Singleton](override val qctx: C) extends ContextUtil def convert[A: Type](nme: String, in: Term): Converted - def asPredicate[A]: (String, Type[A], Term) => Boolean = - (n, tpe, tree) => - val tag = tpe - convert(n, tree)(tag).isSuccess + def asPredicate: (String, TypeRepr, Term) => Boolean = + (n: String, tpe: TypeRepr, tree: Term) => + tpe.asType match + case '[a] => + convert[a](n, tree)(Type.of[a]).isSuccess /** * Substitutes wrappers in tree `t` with the result of `subWrapper`. A wrapper is a Tree of the diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index 88e82fb17..b01b9fd5e 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -235,7 +235,7 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits: // def settingDyn[T](t: Def.Initialize[T]): Def.Initialize[T] = macro settingDynMacroImpl[T] inline def inputTask[A1](inline a: A1): Def.Initialize[InputTask[A1]] = - ${ TaskMacro.inputTaskMacroImpl[A1]('a) } + ${ InputTaskMacro.inputTaskMacroImpl[A1]('a) } // def taskIf[T](a: T): Def.Initialize[Task[T]] = macro taskIfMacroImpl[T] @@ -308,11 +308,17 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits: // result of type A1, previously implemented using ParserInput.parsedMacroImpl[A1]. extension [A1](in: Initialize[Parser[A1]]) - inline def parsed: A1 = ParserInput.wrapInit[A1](Def.toISParser(in)) + inline def parsed: A1 = ParserInput.`initParser_\u2603\u2603`[A1](Def.toISParser(in)) extension [A1](in: Initialize[State => Parser[A1]]) @targetName("parsedISPA1") - inline def parsed: A1 = ParserInput.wrapInit[A1](in) + inline def parsed: A1 = ParserInput.`initParser_\u2603\u2603`[A1](in) + + extension [A1](in: Def.Initialize[InputTask[A1]]) + inline def parsed: Task[A1] = + ParserInput.`initParser_\u2603\u2603`[Task[A1]](Def.toIParser[A1](in)) + + inline def evaluated: A1 = InputWrapper.`wrapInitInputTask_\u2603\u2603`[A1](in) inline def settingKey[A1](inline description: String): SettingKey[A1] = ${ std.KeyMacro.settingKeyImpl[A1]('description) } @@ -379,7 +385,8 @@ end Def // because the target doesn't involve Initialize or anything in Def trait TaskMacroExtra: import sbt.std.ParserInput - // implicit def macroValueT[T](@deprecated("unused", "") in: Task[T]): std.MacroValue[T] = ??? + extension [A1](in: Task[A1]) + inline def value: A1 = std.InputWrapper.`wrapTask_\u2603\u2603`[A1](in) // implicit def macroValueIn[T](@deprecated("unused", "") in: InputTask[T]): std.InputEvaluated[T] = // ??? diff --git a/main-settings/src/main/scala/sbt/InputTask.scala b/main-settings/src/main/scala/sbt/InputTask.scala index 92d6e8eed..89623e2a8 100644 --- a/main-settings/src/main/scala/sbt/InputTask.scala +++ b/main-settings/src/main/scala/sbt/InputTask.scala @@ -69,37 +69,42 @@ object InputTask: def static[T](p: Parser[Task[T]]): InputTask[T] = free(_ => p) def static[I, T](p: Parser[I])(c: I => Task[T]): InputTask[T] = static(p map c) + */ - def free[T](p: State => Parser[Task[T]]): InputTask[T] = make(p) + def free[A1](p: State => Parser[Task[A1]]): InputTask[A1] = make(p) - def free[I, T](p: State => Parser[I])(c: I => Task[T]): InputTask[T] = free(s => p(s) map c) + def free[A1, A2](p: State => Parser[A1])(c: A1 => Task[A2]): InputTask[A2] = + free(s => p(s) map c) - def separate[I, T]( - p: State => Parser[I] - )(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = - separate(Def value p)(action) + def separate[A1, A2]( + p: State => Parser[A1] + )(action: Initialize[A1 => Task[A2]]): Initialize[InputTask[A2]] = + separate(Def.value(p))(action) - def separate[I, T]( - p: Initialize[State => Parser[I]] - )(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = + def separate[A1, A2]( + p: Initialize[State => Parser[A1]] + )(action: Initialize[A1 => Task[A2]]): Initialize[InputTask[A2]] = p.zipWith(action)((parser, act) => free(parser)(act)) + /* /** 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) 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)) + def createDyn[A1, A2]( + p: Initialize[State => Parser[A1]] + )(action: Initialize[Task[A1 => Initialize[Task[A2]]]]): Initialize[InputTask[A2]] = + separate(p)(std.FullInstance.flattenFun[A1, A2](action)) + /* /** A dummy parser that consumes no input and produces nothing useful (unit). */ def emptyParser: State => Parser[Unit] = Types.const(sbt.internal.util.complete.DefaultParsers.success(())) diff --git a/main-settings/src/main/scala/sbt/Structure.scala b/main-settings/src/main/scala/sbt/Structure.scala index cbb48f615..34e07cb3d 100644 --- a/main-settings/src/main/scala/sbt/Structure.scala +++ b/main-settings/src/main/scala/sbt/Structure.scala @@ -236,7 +236,11 @@ sealed trait InputKey[A1] def in(scope: Scope): InputKey[A1] = Scoped.scopedInput(Scope.replaceThis(this.scope)(scope), this.key) - // inline def :=(inline v: A1): Setting[InputTask[A1]] = macro std.TaskMacro.inputTaskAssignMacroImpl[A1] + private inline def inputTaskMacro[A2](inline a: A2): Def.Initialize[InputTask[A2]] = + ${ std.InputTaskMacro.inputTaskMacroImpl('a) } + + inline def :=(inline a: A1): Setting[InputTask[A1]] = + set(inputTaskMacro[A1](a)) final inline def ~=(f: A1 => A1): Setting[InputTask[A1]] = transform(f) diff --git a/main-settings/src/main/scala/sbt/std/InputTaskMacro.scala.scala b/main-settings/src/main/scala/sbt/std/InputTaskMacro.scala.scala new file mode 100644 index 000000000..caa8dc123 --- /dev/null +++ b/main-settings/src/main/scala/sbt/std/InputTaskMacro.scala.scala @@ -0,0 +1,198 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package std + +import sbt.internal.util.Types.Id +import sbt.internal.util.complete.Parser +import scala.quoted.* + +object InputTaskMacro: + import TaskMacro.ContSyntax.* + + def inputTaskMacroImpl[A1: Type](tree: Expr[A1])(using + qctx: Quotes + ): Expr[Def.Initialize[InputTask[A1]]] = + inputTaskMacro0[A1](tree) + + // def inputTaskDynMacroImpl[A1: Type](t: c.Expr[Initialize[Task[A1]]])(using qctx: Quotes): c.Expr[Initialize[InputTask[A1]]] = + // inputTaskDynMacro0[A1](c)(t) + + private[this] def inputTaskMacro0[A1: Type](tree: Expr[A1])(using + qctx: Quotes + ): Expr[Def.Initialize[InputTask[A1]]] = + import qctx.reflect.* + // println(s"tree = ${tree.show}") + iInitializeMacro(tree) { et => + val pt: Expr[State => Parser[Task[A1]]] = iParserMacro(et) { pt => + val tt = iTaskMacro(pt) + // println(s"tt = ${tt.show}") + tt + } + '{ InputTask.make($pt) } + } + + private[this] def iInitializeMacro[F1[_]: Type, A1: Type](tree: Expr[A1])( + f: Expr[A1] => Expr[F1[A1]] + )(using qctx: Quotes): Expr[Def.Initialize[F1[A1]]] = + import qctx.reflect.* + import InputWrapper.* + val convert1 = new InputInitConvert(qctx) + import convert1.Converted + + def wrapInitTask[A2: Type](tree: Term): Term = + val expr = tree.asExprOf[Def.Initialize[Task[A2]]] + '{ + InputWrapper.`wrapTask_\u2603\u2603`[A2](InputWrapper.`wrapInit_\u2603\u2603`[A2]($expr)) + }.asTerm + + def wrapInitParser[A2: Type](tree: Term): Term = + val expr = tree.asExprOf[Def.Initialize[State => Parser[A2]]] + '{ + ParserInput.`parser_\u2603\u2603`[A2]( + InputWrapper.`wrapInit_\u2603\u2603`[State => Parser[A2]]($expr) + ) + }.asTerm + + def wrapInitInput[A2: Type](tree: Term): Term = + val expr = tree.asExprOf[Def.Initialize[InputTask[A2]]] + wrapInput[A2]('{ + InputWrapper.`wrapInit_\u2603\u2603`[InputTask[A2]]($expr) + }.asTerm) + + def wrapInput[A2: Type](tree: Term): Term = + val expr = tree.asExprOf[InputTask[A1]] + '{ + InputWrapper.`wrapTask_\u2603\u2603`[A2]( + ParserInput.`parser_\u2603\u2603`[Task[A2]]($expr.parser) + ) + }.asTerm + + def expand(nme: String, tpeRepr: TypeRepr, tree: Term): Converted = + tpeRepr.asType match + case '[tpe] => + nme match + case WrapInitTaskName => Converted.success(wrapInitTask[tpe](tree)) + case WrapPreviousName => Converted.success(wrapInitTask[tpe](tree)) + case ParserInput.WrapInitName => Converted.success(wrapInitParser[tpe](tree)) + case WrapInitInputName => Converted.success(wrapInitInput[tpe](tree)) + case WrapInputName => Converted.success(wrapInput[tpe](tree)) + case _ => Converted.NotApplicable() + + def conditionInputTaskTree(t: Term): Term = + convert1.transformWrappers( + tree = t, + subWrapper = (nme, tpe, tree, original) => expand(nme, tpe, tree), + owner = Symbol.spliceOwner, + ) + + val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm + val cond = conditionInputTaskTree(tree.asTerm).asExprOf[A1] + convert1.contMapN[A1, Def.Initialize, F1](cond, convert1.appExpr, inner) + + private[this] def iParserMacro[F1[_]: Type, A1: Type](tree: Expr[A1])( + f: Expr[A1] => Expr[F1[A1]] + )(using qctx: Quotes): Expr[State => Parser[F1[A1]]] = + import qctx.reflect.* + val convert1 = new ParserConvert(qctx) + val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm + convert1.contMapN[A1, ParserInstance.F1, F1](tree, convert1.appExpr, inner) + + private[this] def iTaskMacro[A1: Type](tree: Expr[A1])(using qctx: Quotes): Expr[Task[A1]] = + import qctx.reflect.* + val convert1 = new TaskConvert(qctx) + convert1.contMapN[A1, Task, Id](tree, convert1.appExpr) + + /* + private[this] def inputTaskDynMacro0[A1: Type]( + expr: Expr[Def.Initialize[Task[A1]]] + )(using qctx: Quotes): Expr[Def.Initialize[InputTask[A1]]] = { + import qctx.reflect.{ Apply => ApplyTree, * } + // import internal.decorators._ + val tag: Type[A1] = summon[Type[A1]] + // val util = ContextUtil[c.type](c) + val convert1 = new InitParserConvert(qctx) + import convert1.Converted + + // val it = Ident(convert1.singleton(InputTask)) + val isParserWrapper = new InitParserConvert(qctx).asPredicate + val isTaskWrapper = new FullConvert(qctx).asPredicate + val isAnyWrapper = + (n: String, tpe: TypeRepr, tr: Term) => + isParserWrapper(n, tpe, tr) || isTaskWrapper(n, tpe, tr) + val ttree = expr.asTerm + val defs = convert1.collectDefs(ttree, isAnyWrapper) + val checkQual = + util.checkReferences(defs, isAnyWrapper, weakTypeOf[Def.Initialize[InputTask[Any]]]) + + // 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[(Term, TypeRepr, ValDef)] = None + + // original is the Tree being replaced. It is needed for preserving attributes. + def subWrapper(tpe: TypeRepr, qual: Term, original: Term): Tree = + if result.isDefined then + report.errorAndAbort( + "implementation restriction: a dynamic InputTask can only have a single input parser.", + qual.pos, + ) + Literal(UnitConstant()) + else { + // qual.foreach(checkQual) + val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) // val $x: + result = Some((qual, tpe, vd)) + 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) + tree + } + // Tree for InputTask.[, ](arg1)(arg2) + def inputTaskCreate(name: String, tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = { + val typedApp = TypeApply(util.select(it, name), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil) + val app = ApplyTree(ApplyTree(typedApp, arg1 :: Nil), arg2 :: Nil) + Expr[Def.Initialize[InputTask[A1]]](app) + } + // Tree for InputTask.createFree[](arg1) + def inputTaskCreateFree(tpe: Type, arg: Tree) = { + val typedApp = TypeApply(util.select(it, InputTaskCreateFreeName), TypeTree(tpe) :: Nil) + val app = ApplyTree(typedApp, arg :: Nil) + Expr[Def.Initialize[InputTask[A1]]](app) + } + def expandTask[I: Type](dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[I]]] = + if dyn then taskDynMacroImpl[I](c)(c.Expr[Initialize[Task[I]]](tx)) + else taskMacroImpl[I](c)(c.Expr[I](tx)) + def wrapTag[I: Type]: Type[Initialize[Task[I]]] = weakTypeTag + + def sub(name: String, tpe: TypeRepr, qual: Term, oldTree: Term): Converted = + convert1.convert[A1](name, qual) transform { (tree: Term) => + subWrapper(tpe, tree, oldTree) + } + + val inlined = convert1.inlineExtensionProxy(expr.asTerm) + val tx = + convert1.transformWrappers(inlined, sub, Symbol.spliceOwner) + result match { + case Some((p, tpe, param)) => + val fCore = util.createFunction(param :: Nil, tx, functionSym) + val bodyTpe = wrapTag(tag).tpe + val fTpe = util.functionType(tpe :: Nil, bodyTpe) + val fTag = Type[Any](fTpe) // don't know the actual type yet, so use Any + val fInit = expandTask(false, fCore)(fTag).tree + inputTaskCreate(InputTaskCreateDynName, tpe, tag.tpe, p, fInit) + case None => + val init = expandTask[A1](true, tx).tree + inputTaskCreateFree(tag.tpe, init) + } + } + */ +end InputTaskMacro diff --git a/main-settings/src/main/scala/sbt/std/InputWrapper.scala b/main-settings/src/main/scala/sbt/std/InputWrapper.scala index eae014af0..0f75908d0 100644 --- a/main-settings/src/main/scala/sbt/std/InputWrapper.scala +++ b/main-settings/src/main/scala/sbt/std/InputWrapper.scala @@ -64,9 +64,6 @@ object InputWrapper: private[this] def implDetailError = sys.error("This method is an implementation detail and should not be referenced.") - inline def wrapTask[A](in: Any): A = `wrapTask_\u2603\u2603`[A](in) - inline def wrapInit[A](in: Any): A = `wrapInit_\u2603\u2603`[A](in) - /* private[std] def wrapInitInputTask[T: c.WeakTypeTag](using qctx: Quotes)( ts: c.Expr[Any], @@ -237,9 +234,6 @@ object ParserInput: def `initParser_\u2603\u2603`[T](@deprecated("unused", "") i: Any): T = sys.error("This method is an implementation detail and should not be referenced.") - inline def wrap[A1](in: Any): A1 = `parser_\u2603\u2603`[A1](in) - inline def wrapInit[A1](in: Any): A1 = `initParser_\u2603\u2603`[A1](in) - /* private[std] def inputParser[T: c.WeakTypeTag]( using qctx: Quotes diff --git a/main-settings/src/main/scala/sbt/std/Instances.scala b/main-settings/src/main/scala/sbt/std/Instances.scala index 692527ffc..3fde6f9fd 100644 --- a/main-settings/src/main/scala/sbt/std/Instances.scala +++ b/main-settings/src/main/scala/sbt/std/Instances.scala @@ -87,18 +87,23 @@ object FullInstance: (a, data).flatMap { case (a, d) => f(a) evaluate d } }(AList.tuple3[Task[Initialize[Task[A1]]], Task[SS], [a] => Initialize[a] => Initialize[a]]) -/* - def flattenFun[S, T]( - in: Initialize[Task[S => Initialize[Task[A1]]]] - ): Initialize[S => Task[A1]] = { + def flattenFun[A1, A2]( + in: Initialize[Task[A1 => Initialize[Task[A2]]]] + ): Initialize[A1 => Task[A2]] = type K[L[x]] = - AList.T3K[Task[S => Initialize[Task[A1]]], Task[SS], Initialize ~> Initialize]#l[L] - Def.app[K, S => Task[A1]]((in, settingsData, Def.capturedTransformations)) { - case (a: Task[S => Initialize[Task[A1]]], data: Task[SS], f) => { (s: S) => - import TaskExtra.multT2Task - (a, data) flatMap { case (af, d) => f(af(s)) evaluate d } + AList.Tuple3K[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[ + a + ]][L] + Def.app[K, A1 => Task[A2]]((in, settingsData, Def.capturedTransformations)) { + case (a: Task[A1 => Initialize[Task[A2]]] @unchecked, data: Task[SS] @unchecked, f) => { + (s: A1) => + import TaskExtra.multT2Task + (a, data) flatMap { case (af, d) => f(af(s)) evaluate d } } - }(AList.tuple3) - } - */ + }( + AList.tuple3[Task[A1 => Initialize[Task[A2]]], Task[SS], [a] => Initialize[a] => Initialize[ + a + ]] + ) + end FullInstance diff --git a/main-settings/src/main/scala/sbt/std/TaskMacro.scala b/main-settings/src/main/scala/sbt/std/TaskMacro.scala index b3f8107a9..5a1020c48 100644 --- a/main-settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main-settings/src/main/scala/sbt/std/TaskMacro.scala @@ -22,7 +22,6 @@ import sbt.internal.util.appmacro.{ } // import Instance.Transform import sbt.internal.util.{ AList, LinePosition, NoPosition, SourcePosition, ~> } -import sbt.internal.util.complete.Parser import language.experimental.macros import scala.annotation.tailrec @@ -158,15 +157,6 @@ object TaskMacro: $rec.set0($app, $sourcePosition) } - /** Implementation of := macro for tasks. */ - def inputTaskAssignMacroImpl[A1: Type](v: Expr[A1])(using - qctx: Quotes - ): Expr[Setting[InputTask[A1]]] = - val init = inputTaskMacroImpl[A1](v) - // val assign = transformMacroImpl(init.tree)(AssignInitName) - // Expr[Setting[InputTask[A1]]](assign) - ??? - /** Implementation of += macro for settings. */ def settingAppend1Impl[A1: Type, A2: Type](rec: Expr[SettingKey[A1]], v: Expr[A2])(using qctx: Quotes, @@ -238,176 +228,6 @@ object TaskMacro: c.Expr[A1](Literal(Constant(t))) } */ - - def inputTaskMacroImpl[A1: Type](tree: Expr[A1])(using - qctx: Quotes - ): Expr[Initialize[InputTask[A1]]] = - inputTaskMacro0[A1](tree) - - // def inputTaskDynMacroImpl[A1: Type](t: c.Expr[Initialize[Task[A1]]])(using qctx: Quotes): c.Expr[Initialize[InputTask[A1]]] = - // inputTaskDynMacro0[A1](c)(t) - - private[this] def inputTaskMacro0[A1: Type](tree: Expr[A1])(using - qctx: Quotes - ): Expr[Initialize[InputTask[A1]]] = - iInitializeMacro(tree) { et => - val pt = iParserMacro(et) { pt => - iTaskMacro(pt) - } - '{ InputTask.make($pt) } - } - - private[this] def iInitializeMacro[F1[_]: Type, A1: Type](tree: Expr[A1])( - f: Expr[A1] => Expr[F1[A1]] - )(using qctx: Quotes): Expr[Initialize[F1[A1]]] = - import qctx.reflect.* - import InputWrapper.* - val convert1 = new InputInitConvert(qctx) - import convert1.Converted - - def wrapInitTask[A2: Type](tree: Term): Term = - val expr = tree.asExprOf[Initialize[Task[A2]]] - '{ - InputWrapper.wrapTask[A2](InputWrapper.wrapInit[A2]($expr)) - }.asTerm - - def wrapInitParser[A2: Type](tree: Term): Term = - val expr = tree.asExprOf[Initialize[State => Parser[A2]]] - '{ - ParserInput.wrap[A2](InputWrapper.wrapInit[State => Parser[A2]]($expr)) - }.asTerm - - def wrapInitInput[A2: Type](tree: Term): Term = - val expr = tree.asExprOf[Initialize[InputTask[A2]]] - wrapInput[A2]('{ - InputWrapper.wrapInit[InputTask[A2]]($expr) - }.asTerm) - - def wrapInput[A2: Type](tree: Term): Term = - val expr = tree.asExprOf[InputTask[A1]] - '{ - InputWrapper.wrapTask[A2](ParserInput.wrap[Task[A2]]($expr.parser)) - }.asTerm - - def expand(nme: String, tpeRepr: TypeRepr, tree: Term): Converted = - tpeRepr.asType match - case '[tpe] => - nme match - case WrapInitTaskName => Converted.success(wrapInitTask[tpe](tree)) - case WrapPreviousName => Converted.success(wrapInitTask[tpe](tree)) - case ParserInput.WrapInitName => Converted.success(wrapInitParser[tpe](tree)) - case WrapInitInputName => Converted.success(wrapInitInput[tpe](tree)) - case WrapInputName => Converted.success(wrapInput[tpe](tree)) - case _ => Converted.NotApplicable() - - def conditionInputTaskTree(t: Term): Term = - convert1.transformWrappers( - tree = t, - subWrapper = (nme, tpe, tree, original) => expand(nme, tpe, tree), - owner = Symbol.spliceOwner, - ) - - val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm - val cond = conditionInputTaskTree(tree.asTerm).asExprOf[A1] - convert1.contMapN[A1, Def.Initialize, F1](cond, convert1.appExpr, inner) - - private[this] def iParserMacro[F1[_]: Type, A1: Type](tree: Expr[A1])( - f: Expr[A1] => Expr[F1[A1]] - )(using qctx: Quotes): Expr[State => Parser[F1[A1]]] = - import qctx.reflect.* - val convert1 = new ParserConvert(qctx) - val inner: convert1.TermTransform[F1] = (in: Term) => f(in.asExprOf[A1]).asTerm - convert1.contMapN[A1, ParserInstance.F1, F1](tree, convert1.appExpr, inner) - - private[this] def iTaskMacro[A1: Type](tree: Expr[A1])(using qctx: Quotes): Expr[Task[A1]] = - import qctx.reflect.* - val convert1 = new TaskConvert(qctx) - convert1.contMapN[A1, Task, Id](tree, convert1.appExpr) - - /* - private[this] def inputTaskDynMacro0[A1: Type]( - t: Expr[Initialize[Task[A1]]] - )(using qctx: Quotes): Expr[Initialize[InputTask[A1]]] = { - import c.universe.{ Apply => ApplyTree, _ } - import internal.decorators._ - - val tag = implicitly[Type[A1]] - val util = ContextUtil[c.type](c) - val it = Ident(util.singleton(InputTask)) - val isParserWrapper = InitParserConvert.asPredicate(c) - val isTaskWrapper = FullConvert.asPredicate(c) - val isAnyWrapper = (n: String, tpe: Type, tr: Tree) => - isParserWrapper(n, tpe, tr) || isTaskWrapper(n, tpe, tr) - val ttree = t.tree - val defs = util.collectDefs(ttree, isAnyWrapper) - val checkQual = util.checkReferences(defs, isAnyWrapper, weakTypeOf[Initialize[InputTask[Any]]]) - - // 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 - - // 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." - ) - EmptyTree - } else { - qual.foreach(checkQual) - val vd = util.freshValDef(tpe, qual.symbol.pos, functionSym) // val $x: - result = Some((qual, tpe, vd)) - 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) - tree - } - // Tree for InputTask.[, ](arg1)(arg2) - def inputTaskCreate(name: String, tpeA: Type, tpeB: Type, arg1: Tree, arg2: Tree) = { - val typedApp = TypeApply(util.select(it, name), TypeTree(tpeA) :: TypeTree(tpeB) :: Nil) - val app = ApplyTree(ApplyTree(typedApp, arg1 :: Nil), arg2 :: Nil) - c.Expr[Initialize[InputTask[A1]]](app) - } - // Tree for InputTask.createFree[](arg1) - def inputTaskCreateFree(tpe: Type, arg: Tree) = { - val typedApp = TypeApply(util.select(it, InputTaskCreateFreeName), TypeTree(tpe) :: Nil) - val app = ApplyTree(typedApp, arg :: Nil) - c.Expr[Initialize[InputTask[A1]]](app) - } - def expandTask[I: WeakTypeTag](dyn: Boolean, tx: Tree): c.Expr[Initialize[Task[I]]] = - if (dyn) - taskDynMacroImpl[I](c)(c.Expr[Initialize[Task[I]]](tx)) - else - taskMacroImpl[I](c)(c.Expr[I](tx)) - def wrapTag[I: WeakTypeTag]: WeakTypeTag[Initialize[Task[I]]] = weakTypeTag - - def sub(name: String, tpe: Type, qual: Tree, selection: Tree): Converted[c.type] = { - val tag = Type[A1](tpe) - InitParserConvert(c)(name, qual)(tag) transform { tree => - subWrapper(tpe, tree, selection) - } - } - - val tx = util.transformWrappers(ttree, (n, tpe, tree, replace) => sub(n, tpe, tree, replace)) - result match { - case Some((p, tpe, param)) => - val fCore = util.createFunction(param :: Nil, tx, functionSym) - val bodyTpe = wrapTag(tag).tpe - val fTpe = util.functionType(tpe :: Nil, bodyTpe) - val fTag = Type[Any](fTpe) // don't know the actual type yet, so use Any - val fInit = expandTask(false, fCore)(fTag).tree - inputTaskCreate(InputTaskCreateDynName, tpe, tag.tpe, p, fInit) - case None => - val init = expandTask[A1](true, tx).tree - inputTaskCreateFree(tag.tpe, init) - } - } - */ end TaskMacro object DefinableTaskMacro: diff --git a/main-settings/src/test/scala/sbt/std/UsageTest.scala b/main-settings/src/test/scala/sbt/std/UsageTest.scala index 2ca0da508..cb14a2b34 100644 --- a/main-settings/src/test/scala/sbt/std/UsageTest.scala +++ b/main-settings/src/test/scala/sbt/std/UsageTest.scala @@ -11,6 +11,7 @@ import sbt.internal.util.complete import sbt.internal.util.complete.DefaultParsers import sbt.{ Def, InputTask, Task } import sbt.Def.parsed +import sbt.Def.value object UseTask: val set = Def.setting { 23 } @@ -91,30 +92,36 @@ object Assign { // tsk.parsed // "as" //dummy.value.parsed } - // val it2 = Def.inputTask { - // "lit" - // } + val it2 = Def.inputTask { + "lit" + } + + val it3: Initialize[InputTask[String]] = Def.inputTask[String] { + itsk.parsed.value.toString + } + + val it3b: Initialize[InputTask[String]] = Def.inputTask[String] { + tsk.parsed.value + itsk.parsed.value.toString + isk.evaluated + } + + // should not compile: cannot use a task to define the parser + /* val it4 = Def.inputTask { + dummyt.value.parsed + }*/ + // should compile: can use a setting to define the parser + val it5 = Def.inputTask { + dummys.parsed + } - // val it3: Initialize[InputTask[String]] = Def.inputTask[String] { - // tsk.parsed.value + itsk.parsed.value.toString + isk.evaluated - // } - // // should not compile: cannot use a task to define the parser - // /* val it4 = Def.inputTask { - // dummyt.value.parsed - // }*/ - // // should compile: can use a setting to define the parser - // val it5 = Def.inputTask { - // dummys.parsed - // } // val it6 = Def.inputTaskDyn { // val d3 = dummy3.parsed // val i = d3._2 // Def.task { tk.value + i } // } - // val it7 = Def.inputTask { - // it5.parsed - // } + val it7 = Def.inputTask { + it5.parsed + } // def bool: Initialize[Boolean] = Def.setting { true } // def enabledOnly[T](key: Initialize[T]): Initialize[Seq[T]] = Def.setting {