From a1f5933e43831c25fed55969e4d5d2fd530daa2e Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 20 Feb 2012 15:20:54 +0100 Subject: minimalist refactoring to allow annotating trees not tested for performance, but shouldn't add any memory overhead see https://github.com/adriaanm/scala/commit/44362c557f for an example usage --- src/compiler/scala/reflect/runtime/Universe.scala | 5 +++++ src/compiler/scala/tools/nsc/symtab/Positions.scala | 9 +++++++++ src/compiler/scala/tools/nsc/util/Position.scala | 13 ++++++++++++- src/library/scala/reflect/api/Positions.scala | 18 +++++++++++++++--- src/library/scala/reflect/api/Trees.scala | 19 +++++++++++++------ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala index 324fee87ab..7a5dda3d8e 100644 --- a/src/compiler/scala/reflect/runtime/Universe.scala +++ b/src/compiler/scala/reflect/runtime/Universe.scala @@ -39,6 +39,11 @@ class Universe extends SymbolTable { definitions.AnyValClass // force it. + type TreeAnnotation = Position + val NoTreeAnnotation: TreeAnnotation = NoPosition + def positionToAnnotation(pos: Position): TreeAnnotation = pos // TODO + def annotationToPosition(annot: TreeAnnotation): Position = annot //TODO + // establish root association to avoid cyclic dependency errors later classToScala(classOf[java.lang.Object]).initialize diff --git a/src/compiler/scala/tools/nsc/symtab/Positions.scala b/src/compiler/scala/tools/nsc/symtab/Positions.scala index c96c709fb0..680b06f8ce 100644 --- a/src/compiler/scala/tools/nsc/symtab/Positions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Positions.scala @@ -14,6 +14,15 @@ self: scala.tools.nsc.symtab.SymbolTable => type Position = scala.tools.nsc.util.Position val NoPosition = scala.tools.nsc.util.NoPosition + type TreeAnnotation = scala.tools.nsc.util.TreeAnnotation + val NoTreeAnnotation: TreeAnnotation = NoPosition + def positionToAnnotation(pos: Position): TreeAnnotation = pos + def annotationToPosition(annot: TreeAnnotation): Position = annot.pos + override def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = { + if (tree.pos != NoPosition && tree.pos != annot.pos) debugwarn("Overwriting annotation "+ tree.annotation +" of tree "+ tree +" with annotation "+ annot) + // if ((tree.annotation.isInstanceOf[scala.tools.nsc.util.Position] || !annot.isInstanceOf[scala.tools.nsc.util.Position]) && tree.isInstanceOf[Block]) + // println("Updating block from "+ tree.annotation +" to "+ annot) + } def focusPos(pos: Position): Position = pos.focus def isRangePos(pos: Position): Boolean = pos.isRange def showPos(pos: Position): String = pos.show diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 53c767be20..bc74717366 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -33,6 +33,16 @@ object Position { } } +/** + * A tree does not directly store a Position. It stores a TreeAnnotation, which /typically/ is a Position. + * + * A TreeAnnotion may encompass more than just a Position, though, depending on the exact subclass of TreeAnnotation. + */ +trait TreeAnnotation { + def pos: Position +} + + /** The Position class and its subclasses represent positions of ASTs and symbols. * Except for NoPosition and FakePos, every position refers to a SourceFile * and to an offset in the sourcefile (its `point`). For batch compilation, @@ -77,7 +87,8 @@ object Position { * pos.makeTransparent converts an opaque range position into a transparent one. * returns all other positions unchanged. */ -trait Position { +trait Position extends TreeAnnotation { + def pos: Position = this /** An optional value containing the source file referred to by this position, or * None if not defined. diff --git a/src/library/scala/reflect/api/Positions.scala b/src/library/scala/reflect/api/Positions.scala index 181e7c1525..4c8c33bec8 100644 --- a/src/library/scala/reflect/api/Positions.scala +++ b/src/library/scala/reflect/api/Positions.scala @@ -1,9 +1,21 @@ package scala.reflect package api -trait Positions { +trait Positions { self: Universe => + /** TreeAnnotation is a generalisation of Position. + * + * TreeAnnotation cannot be an upperbound of Position since the corresponding classes + * must live outside of the universe for backwards compatibility (see scala.tools.nsc.util.Position). + * Thus, represent subtyping as coercions. + * + * Typically, positionToAnnotation is the identity, and annotationToPosition returns annot.pos + */ + type TreeAnnotation // <: { def pos: Position } + val NoTreeAnnotation: TreeAnnotation + implicit def positionToAnnotation(pos: Position): TreeAnnotation // = pos + def annotationToPosition(annot: TreeAnnotation): Position // = annot.pos + def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = () // check that annot may overwrite tree.annot - type Position + type Position // <: TreeAnnotation, but not practical to enforce this (would require moving Position, SourceFile, Reporter,... into the universe) val NoPosition: Position - } \ 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 466c380cef..4ee13adf52 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -74,17 +74,24 @@ trait Trees { self: Universe => val id = nodeCount nodeCount += 1 - private[this] var rawpos: Position = NoPosition - /** Prefix under which to print this tree type. Defaults to product * prefix (e.g. DefTree) but because that is used in reification * it cannot be altered without breaking reflection. */ def printingPrefix = productPrefix - def pos = rawpos - def pos_=(pos: Position) = rawpos = pos - def setPos(pos: Position): this.type = { rawpos = pos; this } + def pos: Position = annotationToPosition(rawannot) + def pos_=(pos: Position): Unit = annotation = pos + def setPos(newpos: Position): this.type = { pos = newpos; this } + + private[this] var rawannot: TreeAnnotation = NoTreeAnnotation + def annotation: TreeAnnotation = rawannot + def annotation_=(annot: TreeAnnotation): Unit = { + _checkSetAnnotation(this, annot) + rawannot = annot + } + + def setAnnotation(annot: TreeAnnotation): this.type = { annotation = annot; this } private[this] var rawtpe: Type = _ @@ -223,7 +230,7 @@ trait Trees { self: Universe => duplicateTree(this).asInstanceOf[this.type] private[scala] def copyAttrs(tree: Tree): this.type = { - pos = tree.pos + annotation = tree.annotation tpe = tree.tpe if (hasSymbol) symbol = tree.symbol this -- cgit v1.2.3