mirror of https://github.com/sbt/sbt.git
Use @compileTimeOnly for .value and .parsed methods.
Needed to set position on wrapper method for correct error message position.
This commit is contained in:
parent
ae74fff88c
commit
9ab1b98d2a
|
|
@ -16,6 +16,7 @@ package sbt
|
|||
import Types._
|
||||
|
||||
import language.experimental.macros
|
||||
import reflect.internal.annotations.compileTimeOnly
|
||||
|
||||
sealed trait Scoped { def scope: Scope; val key: AttributeKey[_] }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package std
|
|||
import language.experimental.macros
|
||||
import scala.reflect._
|
||||
import reflect.macros._
|
||||
import reflect.internal.annotations.compileTimeOnly
|
||||
|
||||
/** Instance for the monad/applicative functor for plain Tasks. */
|
||||
object TaskInstance extends MonadInstance
|
||||
|
|
@ -220,39 +221,43 @@ object TaskMacro
|
|||
}
|
||||
|
||||
sealed abstract class MacroValue[T] {
|
||||
@compileTimeOnly("`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.")
|
||||
def value: T = macro std.TaskMacro.valueMacroImpl[T]
|
||||
}
|
||||
|
||||
def valueMacroImpl[T: c.WeakTypeTag](c: Context): c.Expr[T] =
|
||||
ContextUtil.selectMacroImpl[T,Any](c)( ts => InputWrapper.wrapKey[T](c)(ts) )
|
||||
ContextUtil.selectMacroImpl[T,Any](c)( (ts,pos) => InputWrapper.wrapKey[T](c)(ts,pos) )
|
||||
|
||||
sealed abstract class RawParserInput[T] {
|
||||
@compileTimeOnly("`parsed` can only be used within an input task macro, such as := or Def.inputTask.")
|
||||
def parsed: T = macro std.TaskMacro.rawParserMacro[T]
|
||||
}
|
||||
sealed abstract class InitParserInput[T] {
|
||||
@compileTimeOnly("`parsed` can only be used within an input task macro, such as := or Def.inputTask.")
|
||||
def parsed: T = macro std.TaskMacro.initParserMacro[T]
|
||||
}
|
||||
sealed abstract class StateParserInput[T] {
|
||||
@compileTimeOnly("`parsed` can only be used within an input task macro, such as := or Def.inputTask.")
|
||||
def parsed: T = macro std.TaskMacro.stateParserMacro[T]
|
||||
}
|
||||
|
||||
/** Implements `Parser[T].parsed` by wrapping the Parser with the ParserInput wrapper.*/
|
||||
def rawParserMacro[T: c.WeakTypeTag](c: Context): c.Expr[T] =
|
||||
ContextUtil.selectMacroImpl[T, Parser[T]](c) { p => c.universe.reify {
|
||||
ParserInput.parser_\u2603\u2603[T](InputTask.parserAsInput(p.splice))
|
||||
}}
|
||||
ContextUtil.selectMacroImpl[T, Parser[T]](c) { (p,pos) =>
|
||||
ParserInput.wrap[T](c)(c.universe.reify { InputTask.parserAsInput(p.splice) }, pos)
|
||||
}
|
||||
|
||||
/** Implements the `Initialize[Parser[T]].parsed` macro by wrapping the input with the ParserInput wrapper.*/
|
||||
def initParserMacro[T: c.WeakTypeTag](c: Context): c.Expr[T] =
|
||||
ContextUtil.selectMacroImpl[T, Initialize[Parser[T]]](c) { t => c.universe.reify {
|
||||
ParserInput.parser_\u2603\u2603[T](InputTask.initParserAsInput(t.splice))
|
||||
}}
|
||||
ContextUtil.selectMacroImpl[T, Initialize[Parser[T]]](c) { (t,pos) =>
|
||||
ParserInput.wrap[T](c)(c.universe.reify { InputTask.initParserAsInput(t.splice) }, pos)
|
||||
}
|
||||
|
||||
/** Implements the `Initialize[State => Parser[T]].parsed` macro by wrapping the input with the ParserInput wrapper.*/
|
||||
def stateParserMacro[T: c.WeakTypeTag](c: Context): c.Expr[T] =
|
||||
ContextUtil.selectMacroImpl[T, Initialize[State => Parser[T]]](c) { t => c.universe.reify {
|
||||
ParserInput.parser_\u2603\u2603[T](t.splice)
|
||||
}}
|
||||
ContextUtil.selectMacroImpl[T, Initialize[State => Parser[T]]](c) { (t,pos) =>
|
||||
ParserInput.wrap[T](c)(t, pos)
|
||||
}
|
||||
|
||||
/** Implementation detail. The method temporarily holds the input parser (as a Tree, at compile time) until the input task macro processes it. */
|
||||
object ParserInput {
|
||||
|
|
@ -261,8 +266,11 @@ object TaskMacro
|
|||
* The user should never see this method because it is compile-time only and only used internally by the task macros.*/
|
||||
val WrapName = "parser_\u2603\u2603"
|
||||
|
||||
// This method should be annotated as compile-time only when that feature is implemented
|
||||
@compileTimeOnly("`parsed` can only be used within an input task macro, such as := or Def.inputTask.")
|
||||
def parser_\u2603\u2603[T](i: Initialize[State => Parser[T]]): T = error("This method is an implementation detail and should not be referenced.")
|
||||
|
||||
def wrap[T: c.WeakTypeTag](c: Context)(ts: c.Expr[Any], pos: c.Position): c.Expr[T] =
|
||||
InputWrapper.wrapImpl[T,ParserInput.type](c, ParserInput, WrapName)(ts, pos)
|
||||
}
|
||||
|
||||
def inputTaskMacroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Initialize[InputTask[T]]] =
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
libraryDependencies += "org.scala-sbt" % "sbt" % sbtVersion.value
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import sbt._
|
||||
import Def.Initialize
|
||||
import complete.{DefaultParsers, Parser}
|
||||
|
||||
object A {
|
||||
val x1: Initialize[Task[Int]] = Def.task { 3 }
|
||||
val y1 = Def.task { x1.value }
|
||||
|
||||
val x2: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) }
|
||||
val y2 = Def.inputTask { x1.value + x2.parsed }
|
||||
|
||||
val x3: Initialize[Int] = Def.setting { 3 }
|
||||
val y3 = Def.setting { x3.value }
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import sbt._
|
||||
import Def.Initialize
|
||||
|
||||
object A {
|
||||
val x1: Initialize[Task[Int]] = Def.task { 3 }
|
||||
val y1 = x1.value
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import sbt._
|
||||
import Def.Initialize
|
||||
import complete.{DefaultParsers, Parser}
|
||||
|
||||
object A {
|
||||
val x1: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) }
|
||||
val y1 = Def.task { x1.parsed }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
$ copy-file changes/A1.scala A.scala
|
||||
> compile
|
||||
|
||||
$ copy-file changes/A2.scala A.scala
|
||||
-> compile
|
||||
|
||||
$ copy-file changes/A3.scala A.scala
|
||||
-> compile
|
||||
|
|
@ -20,11 +20,11 @@ object ContextUtil {
|
|||
*
|
||||
* Given `myImplicitConversion(someValue).extensionMethod`, where `extensionMethod` is a macro that uses this
|
||||
* method, the result of this method is `f(<Tree of someValue>)`. */
|
||||
def selectMacroImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: Context)(f: c.Expr[S] => c.Expr[T]): c.Expr[T] =
|
||||
def selectMacroImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: Context)(f: (c.Expr[S], c.Position) => c.Expr[T]): c.Expr[T] =
|
||||
{
|
||||
import c.universe._
|
||||
c.macroApplication match {
|
||||
case Select(Apply(_, t :: Nil), _) => f( c.Expr[S](t) )
|
||||
case s @ Select(Apply(_, t :: Nil), tp) => f( c.Expr[S](t), s.pos )
|
||||
case x => unexpectedTree(x)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ trait MonadInstance extends Instance
|
|||
|
||||
import scala.reflect._
|
||||
import macros._
|
||||
import reflect.internal.annotations.compileTimeOnly
|
||||
|
||||
// This needs to be moved to main/settings
|
||||
object InputWrapper
|
||||
{
|
||||
/** The name of the wrapper method should be obscure.
|
||||
|
|
@ -35,22 +37,26 @@ object InputWrapper
|
|||
* The user should never see this method because it is compile-time only and only used internally by the task macro system.*/
|
||||
final val WrapName = "wrap_\u2603\u2603"
|
||||
|
||||
// This method should be annotated as compile-time only when that feature is implemented
|
||||
@compileTimeOnly("`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.")
|
||||
def wrap_\u2603\u2603[T](in: Any): T = error("This method is an implementation detail and should not be referenced.")
|
||||
|
||||
/** Wraps an arbitrary Tree in a call to the `wrap` method of this module for later processing by an enclosing macro.
|
||||
def wrapKey[T: c.WeakTypeTag](c: Context)(ts: c.Expr[Any], pos: c.Position): c.Expr[T] = wrapImpl[T,InputWrapper.type](c, InputWrapper, WrapName)(ts, pos)
|
||||
|
||||
/** Wraps an arbitrary Tree in a call to the `<s>.<wrapName>` method of this module for later processing by an enclosing macro.
|
||||
* The resulting Tree is the manually constructed version of:
|
||||
*
|
||||
* `c.universe.reify { InputWrapper.<WrapName>[T](ts.splice) }`
|
||||
* `c.universe.reify { <s>.<wrapName>[T](ts.splice) }`
|
||||
*/
|
||||
def wrapKey[T: c.WeakTypeTag](c: Context)(ts: c.Expr[Any]): c.Expr[T] =
|
||||
def wrapImpl[T: c.WeakTypeTag, S <: AnyRef with Singleton](c: Context, s: S, wrapName: String)(ts: c.Expr[Any], pos: c.Position)(implicit it: c.TypeTag[s.type]): c.Expr[T] =
|
||||
{
|
||||
import c.universe.{Apply=>ApplyTree,_}
|
||||
val util = new ContextUtil[c.type](c)
|
||||
val iw = util.singleton(InputWrapper)
|
||||
val iw = util.singleton(s)
|
||||
val tpe = c.weakTypeOf[T]
|
||||
val nme = newTermName(WrapName).encoded
|
||||
val tree = ApplyTree(TypeApply(Select(Ident(iw), nme), TypeTree(tpe) :: Nil), ts.tree :: Nil)
|
||||
val nme = newTermName(wrapName).encoded
|
||||
val sel = Select(Ident(iw), nme)
|
||||
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)
|
||||
c.Expr[T](tree)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue