From aefad9c0334f78469b67e5c485c185417a335913 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 10 Jan 2013 16:06:12 -0500 Subject: [PATCH] when looking for the enclosing val definition in definingValName, allow the macro to be in an expression --- .../src/main/scala/sbt/std/KeyMacro.scala | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/main/settings/src/main/scala/sbt/std/KeyMacro.scala b/main/settings/src/main/scala/sbt/std/KeyMacro.scala index c35819e8f..d476c1b5f 100644 --- a/main/settings/src/main/scala/sbt/std/KeyMacro.scala +++ b/main/settings/src/main/scala/sbt/std/KeyMacro.scala @@ -5,7 +5,7 @@ package std import scala.reflect._ import reflect.macros._ -object KeyMacro +private[sbt] object KeyMacro { def settingKeyImpl[T: c.WeakTypeTag](c: Context)(description: c.Expr[String]): c.Expr[SettingKey[T]] = keyImpl[T, SettingKey[T]](c) { (name, mf) => @@ -23,21 +23,24 @@ object KeyMacro def keyImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: Context)(f: (c.Expr[String], c.Expr[Manifest[T]]) => c.Expr[S]): c.Expr[S] = { import c.universe.{Apply=>ApplyTree,_} - val enclosingValName = definingValName(c) + val enclosingValName = definingValName(c, methodName => s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`.""") val name = c.Expr[String]( Literal(Constant(enclosingValName)) ) val mf = c.Expr[Manifest[T]](c.inferImplicitValue( weakTypeOf[Manifest[T]] ) ) f(name, mf) } - def definingValName(c: Context): String = + def definingValName(c: Context, invalidEnclosingTree: String => String): String = { import c.universe.{Apply=>ApplyTree,_} val methodName = c.macroApplication.symbol.name.decoded - enclosingTrees(c) match { - case vd @ ValDef(_, name, _, _) :: ts => name.decoded - case _ => - c.error(c.enclosingPosition, s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`.""") - "" - } + def enclosingVal(trees: List[c.Tree]): String = + trees match { + case vd @ ValDef(_, name, _, _) :: ts => name.decoded + case (_: ApplyTree | _: Select | _: TypeApply) :: xs => enclosingVal(xs) + case _ => + c.error(c.enclosingPosition, invalidEnclosingTree(methodName)) + "" + } + enclosingVal(enclosingTrees(c).toList) } def enclosingTrees(c: Context): Seq[c.Tree] = c.asInstanceOf[reflect.macros.runtime.Context].callsiteTyper.context.enclosingContextChain.map(_.tree.asInstanceOf[c.Tree])