summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/Trees.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-10-30 11:48:08 +1000
committerJason Zaugg <jzaugg@gmail.com>2014-10-30 11:48:08 +1000
commitd056439a2762b342f66759de654f0dadb01f5e9a (patch)
tree27409f6ecd5ce1ebd855b8b5c2e4a346b881152f /src/reflect/scala/reflect/internal/Trees.scala
parentbdae51d6a8f18a5456a32c350cb551d42a3cb6c6 (diff)
downloadscala-d056439a2762b342f66759de654f0dadb01f5e9a.tar.gz
scala-d056439a2762b342f66759de654f0dadb01f5e9a.tar.bz2
scala-d056439a2762b342f66759de654f0dadb01f5e9a.zip
SI-8947 Avoid cross talk between tag materializers and reify
After a macro has been expanded, the expandee are expansion are bidirectionally linked with tree attachments. Reify uses the back reference to replace the expansion with the expandee in the reified tree. It also has some special cases to replace calls to macros defined in scala-compiler.jar with `Predef.implicitly[XxxTag[T]]`. This logic lives in `Reshape`. However, the expansion of a macro may be `EmptyTree`. This is the case when a tag materializer macro fails. User defined macros could do the also expand to `EmptyTree`. In the enclosed test case, the error message that the tag materializer issued ("cannot materialize class tag for unsplicable type") is not displayed as the typechecker finds another means of making the surrounding expression typecheck. However, the macro engine attaches a backreference to the materializer macro on `EmpytyTree`! Later, when `reify` reshapes a tree, every occurance of `EmptyTree` will be replaced by a call to `implicitly`. This commit expands the domain of `CannotHaveAttrs`, which is mixed in to `EmptyTree`. It silently ignores all attempts to mutate attachments. Unlike similar code that discards mutations of its type and position, I have refrained from issuing a developer warning in this case, as to silence this I would need to go and add a special case at any places adding attachments.
Diffstat (limited to 'src/reflect/scala/reflect/internal/Trees.scala')
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala7
1 files changed, 7 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 9dc4baee32..26e9c7f89d 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -10,6 +10,7 @@ package internal
import Flags._
import pickling.PickleFormat._
import scala.collection.{ mutable, immutable }
+import scala.reflect.macros.Attachments
import util.Statistics
trait Trees extends api.Trees {
@@ -1075,6 +1076,12 @@ trait Trees extends api.Trees {
override def setType(t: Type) = { requireLegal(t, NoType, "tpe"); this }
override def tpe_=(t: Type) = setType(t)
+ // We silently ignore attempts to add attachments to `EmptyTree`. See SI-8947 for an
+ // example of a bug in macro expansion that this solves.
+ override def setAttachments(attachments: Attachments {type Pos = Position}): this.type = this
+ override def updateAttachment[T: ClassTag](attachment: T): this.type = this
+ override def removeAttachment[T: ClassTag]: this.type = this
+
private def requireLegal(value: Any, allowed: Any, what: String) = (
if (value != allowed) {
log(s"can't set $what for $self to value other than $allowed")