diff options
Diffstat (limited to 'src/library')
-rw-r--r-- | src/library/scala/reflect/api/Attachment.scala | 9 | ||||
-rw-r--r-- | src/library/scala/reflect/api/Trees.scala | 43 |
2 files changed, 39 insertions, 13 deletions
diff --git a/src/library/scala/reflect/api/Attachment.scala b/src/library/scala/reflect/api/Attachment.scala index 9fa5ceb0fb..50f55b4aa5 100644 --- a/src/library/scala/reflect/api/Attachment.scala +++ b/src/library/scala/reflect/api/Attachment.scala @@ -7,8 +7,6 @@ package api * Attachments have to carry positions, because we don't want to introduce even a single additional field in Tree * imposing an unnecessary memory tax because of something that will not be used in most cases. */ -// [Eugene] with the introduction of `attach` and `payload[T]` users don't need to create custom attachments anymore -// however, we cannot move attachments to scala.reflect.internal, because they are used in Trees, which are implemented completely in scala.reflect.api trait Attachment { /** Gets the underlying position */ def pos: Position @@ -22,3 +20,10 @@ trait Attachment { /** Creates a copy of this attachment with its payload updated */ def withPayload(newPayload: Any): Attachment } + +// [Eugene] with the introduction of `attach` and `attachment[T]` users don't need to create custom attachments anymore +// however, we cannot move attachments to scala.reflect.internal, because they are used in Trees, which are implemented completely in scala.reflect.api +private[scala] case class NontrivialAttachment(pos: api.Position, payload: collection.mutable.ListBuffer[Any]) extends Attachment { + def withPos(newPos: api.Position) = copy(pos = newPos, payload = payload) + def withPayload(newPayload: Any) = copy(pos = pos, payload = newPayload.asInstanceOf[collection.mutable.ListBuffer[Any]]) +}
\ No newline at end of file diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 7548a6bdc0..6e2e8261e7 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -85,18 +85,39 @@ trait Trees { self: Universe => def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos) // the "withPos" part is crucial to robustness def setPos(newpos: Position): this.type = { pos = newpos; this } + // [Eugene] can we make this more type-safe private var rawatt: Attachment = NoPosition - private case class NontrivialAttachment(pos: api.Position, payload: Any) extends Attachment { - def withPos(newPos: api.Position) = copy(pos = newPos, payload = payload) - def withPayload(newPayload: Any) = copy(pos = pos, payload = newPayload) - } - // todo. annotate T with ClassTag and make pattern matcher use it - // todo. support multiple attachments, and remove the assignment. only leave attach/detach -// def attachment[T]: T = rawatt.payload.asInstanceOf[T] -// def attachmentOpt[T]: Option[T] = try { Some(rawatt.payload.asInstanceOf[T]) } catch { case _: Throwable => None } - def attachment: Any = rawatt.payload - def attachment_=(att: Any): Unit = rawatt = NontrivialAttachment(pos, att) - def setAttachment(att: Any): this.type = { attachment = att; this } + def attach(att: Any): Unit = + rawatt match { + case NontrivialAttachment(pos, payload) => + val index = payload.indexWhere(p => p.getClass == att.getClass) + if (index == -1) payload += att + else payload(index) = att + case _ => + rawatt = NontrivialAttachment(pos, collection.mutable.ListBuffer[Any](att)) + } + def withAttachment(att: Any): this.type = { attach(att); this } + def detach(att: Any): Unit = + detach(att.getClass) + def detach(clazz: java.lang.Class[_]): Unit = + rawatt match { + case NontrivialAttachment(pos, payload) => + val index = payload.indexWhere(p => p.getClass == clazz) + if (index != -1) payload.remove(index) + case _ => + // do nothing + } + def withoutAttachment(att: Any): this.type = { detach(att); this } + def attachment[T: ClassTag]: T = attachmentOpt[T] getOrElse { throw new Error("no attachment of type %s".format(classTag[T].erasure)) } + def attachmentOpt[T: ClassTag]: Option[T] = + rawatt match { + case NontrivialAttachment(pos, payload) => + val index = payload.indexWhere(p => p.getClass == classTag[T].erasure) + if (index != -1) Some(payload(index).asInstanceOf[T]) + else None + case _ => + None + } private[this] var rawtpe: Type = _ |