diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-04 22:49:16 -0700 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-04 22:49:16 -0700 |
commit | 6e1243ba2eb2acf3f1fb2b397c0c22ea0e746f1a (patch) | |
tree | 95f5165a2a73d6c2159ea5f2e6cc012596bc3b84 /core/src/main/scala/forge/Target.scala | |
parent | 57087e0f2b91d7b906ddda6a7078fa36fdabbbcb (diff) | |
download | mill-6e1243ba2eb2acf3f1fb2b397c0c22ea0e746f1a.tar.gz mill-6e1243ba2eb2acf3f1fb2b397c0c22ea0e746f1a.tar.bz2 mill-6e1243ba2eb2acf3f1fb2b397c0c22ea0e746f1a.zip |
First pass at providing good compile errors to invalid uses of the `T{...}` macro: we should only allow you to `Target#apply()` on expressions whose values come from outside the `T{...}` block
Diffstat (limited to 'core/src/main/scala/forge/Target.scala')
-rw-r--r-- | core/src/main/scala/forge/Target.scala | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/core/src/main/scala/forge/Target.scala b/core/src/main/scala/forge/Target.scala index 635acb8e..a829d433 100644 --- a/core/src/main/scala/forge/Target.scala +++ b/core/src/main/scala/forge/Target.scala @@ -51,13 +51,33 @@ object Target{ } def impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = { import c.universe._ + def rec(t: Tree): Iterator[c.Tree] = Iterator(t) ++ t.children.flatMap(rec(_)) val bound = collection.mutable.Buffer.empty[(c.Tree, Symbol)] - val OptionGet = c.universe.typeOf[Target[_]].member(TermName("apply")) + val targetApplySym = c.universe.typeOf[Target[_]].member(TermName("apply")) // Derived from @olafurpg's // https://gist.github.com/olafurpg/596d62f87bf3360a29488b725fbc7608 + val (startPos, endPos) = rec(t.tree) + .map(t => (t.pos.start, t.pos.end)) + .reduce[(Int, Int)]{ case ((s1, e1), (s2, e2)) => (math.min(s1, s2), math.max(e1, e2))} + + val macroSource = t.tree.pos.source val transformed = c.internal.typingTransform(t.tree) { - case (t @ q"$fun.apply()", api) if t.symbol == OptionGet => + case (t @ q"$fun.apply()", api) if t.symbol == targetApplySym => + + val used = rec(t) + val banned = used.filter(x => + x.symbol.pos.source == macroSource && + x.symbol.pos.start >= startPos && + x.symbol.pos.end <= endPos + ) + if (banned.hasNext){ + val banned0 = banned.next() + c.abort( + banned0.pos, + "Target#apply() call cannot use `" + banned0.symbol + "` defined within the T{...} block" + ) + } val tempName = c.freshName(TermName("tmp")) val tempSym = c.internal.newTermSymbol(api.currentOwner, tempName) c.internal.setInfo(tempSym, t.tpe) @@ -77,7 +97,7 @@ object Target{ def wrapCached[T](c: Context)(t: c.Tree) = { import c.universe._ val owner = c.internal.enclosingOwner - val ownerIsCacherClass = owner.owner.asClass.baseClasses.exists(_.fullName == "forge.Target.Cacher") + val ownerIsCacherClass = owner.owner.isClass && owner.owner.asClass.baseClasses.exists(_.fullName == "forge.Target.Cacher") if (ownerIsCacherClass && !owner.isMethod){ c.abort( |