aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Trees.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-02-18 15:29:38 +0100
committerMartin Odersky <odersky@gmail.com>2013-02-18 15:29:38 +0100
commit5c9433161e116704730693254fdaf161c69cbcb5 (patch)
tree6c9adc3d7e3b91ee07f7335aac0479df68d67af2 /src/dotty/tools/dotc/core/Trees.scala
parent2b4a19e80a643dfdf8eea5fa40811f76edb27be3 (diff)
downloaddotty-5c9433161e116704730693254fdaf161c69cbcb5.tar.gz
dotty-5c9433161e116704730693254fdaf161c69cbcb5.tar.bz2
dotty-5c9433161e116704730693254fdaf161c69cbcb5.zip
Improved position handling.
1. All positions are range position. 2. Improved position API 3. renamed Offset to Coord, and made sure indices cannot be confused with positions. 4. Trees now automatically get positions that enclose their subtree's positions. 5. typed DefTrees contain positions that also enclose their symbol's position. To make this work well, a symbol's coord should point to the introducing keyword (e.g. def, val, class).
Diffstat (limited to 'src/dotty/tools/dotc/core/Trees.scala')
-rw-r--r--src/dotty/tools/dotc/core/Trees.scala176
1 files changed, 127 insertions, 49 deletions
diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala
index 25226c660..1245119f2 100644
--- a/src/dotty/tools/dotc/core/Trees.scala
+++ b/src/dotty/tools/dotc/core/Trees.scala
@@ -2,6 +2,7 @@ package dotty.tools.dotc.core
import Types._, Names._, Flags._, Positions._, Contexts._, Constants._, SymDenotations._, Symbols._
import Denotations._, StdNames._
+import annotation.tailrec
object Trees {
@@ -30,17 +31,29 @@ object Trees {
* nodes.
*/
abstract class Tree[T] extends DotClass {
+
+ /** The tree's position. Except
+ * for Shared nodes, it is always ensured that a tree's position
+ * contains the positions of all its subtrees.
+ */
def pos: Position
+ /** The typeconstructor at the root of the tree */
type ThisTree[T] <: Tree[T]
protected var _tpe: T = _
+ /** The type of the tree. In case of an untyped tree,
+ * an UnAssignedTypeException is thrown.
+ */
def tpe: T = {
if (_tpe == null) throw new UnAssignedTypeException(this)
_tpe
}
+ /** Return a typed tree that's isomorphic to this tree, but has given
+ * type.
+ */
def withType(tpe: Type): ThisTree[Type] = {
val tree =
(if (_tpe == null ||
@@ -50,12 +63,22 @@ object Trees {
tree.asInstanceOf[ThisTree[Type]]
}
+ /** The denotation referred to by this tree, NoDenotation where not applicable */
def denot(implicit ctx: Context): Denotation = NoDenotation
+
+ /** The symbol defined by ot referred to by this tree, NoSymbol where not applicable */
def symbol(implicit ctx: Context): Symbol = NoSymbol
+ /** Does this tree represent a type? */
def isType: Boolean = false
+
+ /** Does this tree represent a term? */
def isTerm: Boolean = false
+
+ /** Does this tree represent a definition or declaration? */
def isDef: Boolean = false
+
+ /** Is this tree either the empty tree or the empty ValDef? */
def isEmpty: Boolean = false
}
@@ -68,16 +91,16 @@ object Trees {
// ------ Categories of trees -----------------------------------
- /** Tree is definitely a type. Note that some trees
- * have isType = true without being TypTrees (e.g. Ident, AnnotatedTree)
+ /** Instances of this class are trees for which isType is definitely true.
+ * Note that some trees have isType = true without being TypTrees (e.g. Ident, AnnotatedTree)
*/
trait TypTree[T] extends Tree[T] {
type ThisTree[T] <: TypTree[T]
override def isType = true
}
- /** Tree is definitely a term. Note that some trees
- * have isType = true without being TypTrees (e.g. Ident, AnnotatedTree)
+ /** Instances of this class are trees for which isTerm is definitely true.
+ * Note that some trees have isTerm = true without being TermTrees (e.g. Ident, AnnotatedTree)
*/
trait TermTree[T] extends Tree[T] {
type ThisTree[T] <: TermTree[T]
@@ -97,7 +120,7 @@ object Trees {
}
}
- /** Tree's symbol/isType/isTerm properties come from a subtree identifier
+ /** Tree's symbol/isType/isTerm properties come from a subtree identified
* by `forwardTo`.
*/
abstract class ProxyTree[T] extends Tree[T] {
@@ -123,6 +146,7 @@ object Trees {
override def isTerm = name.isTermName
}
+ /** Tree represents a definition */
abstract class DefTree[T] extends NameTree[T] {
type ThisTree[T] <: DefTree[T]
override def isDef = true
@@ -131,28 +155,32 @@ object Trees {
// ----------- Tree case classes ------------------------------------
/** name */
- case class Ident[T] (name: Name)(implicit val pos: Position)
+ case class Ident[T] (name: Name)(implicit cpos: Position)
extends RefTree[T] {
type ThisTree[T] = Ident[T]
+ val pos = cpos
def qualifier: Tree[T] = EmptyTree[T]
}
/** qualifier.name */
- case class Select[T](qualifier: Tree[T], name: Name)(implicit val pos: Position)
+ case class Select[T](qualifier: Tree[T], name: Name)(implicit cpos: Position)
extends RefTree[T] {
type ThisTree[T] = Select[T]
+ val pos = cpos union qualifier.pos
}
/** qual.this */
- case class This[T](qual: TypeName)(implicit val pos: Position)
+ case class This[T](qual: TypeName)(implicit cpos: Position)
extends SymTree[T] with TermTree[T] {
type ThisTree[T] = This[T]
+ val pos = cpos
}
/** C.super[mix], where qual = C.this */
- case class Super[T](qual: Tree[T], mix: TypeName)(implicit val pos: Position)
+ case class Super[T](qual: Tree[T], mix: TypeName)(implicit cpos: Position)
extends ProxyTree[T] with TermTree[T] {
type ThisTree[T] = Super[T]
+ val pos = cpos union qual.pos
def forwardTo = qual
}
@@ -164,82 +192,95 @@ object Trees {
}
/** fun(args) */
- case class Apply[T](fun: Tree[T], args: List[Tree[T]])(implicit val pos: Position)
+ case class Apply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends GenericApply[T] {
type ThisTree[T] = Apply[T]
+ val pos = unionPos(cpos union fun.pos, args)
}
/** fun[args] */
- case class TypeApply[T](fun: Tree[T], args: List[Tree[T]])(implicit val pos: Position)
+ case class TypeApply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends GenericApply[T] {
type ThisTree[T] = TypeApply[T]
+ val pos = unionPos(cpos union fun.pos, args)
}
/** const */
- case class Literal[T](const: Constant)(implicit val pos: Position)
+ case class Literal[T](const: Constant)(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Literal[T]
+ val pos = cpos
}
/** new tpt, but no constructor call */
- case class New[T](tpt: Tree[T])(implicit val pos: Position)
+ case class New[T](tpt: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = New[T]
+ val pos = cpos union tpt.pos
}
/** (left, right) */
- case class Pair[T](left: Tree[T], right: Tree[T])(implicit val pos: Position)
+ case class Pair[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Pair[T]
+ val pos = cpos union left.pos union right.pos
}
/** expr : tpt */
- case class Typed[T](expr: Tree[T], tpt: Tree[T])(implicit val pos: Position)
+ case class Typed[T](expr: Tree[T], tpt: Tree[T])(implicit cpos: Position)
extends ProxyTree[T] with TermTree[T] {
type ThisTree[T] = Typed[T]
+ val pos = cpos union expr.pos union tpt.pos
def forwardTo = expr
}
/** name = arg, in a parameter list */
- case class NamedArg[T](name: Name, arg: Tree[T])(implicit val pos: Position)
+ case class NamedArg[T](name: Name, arg: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = NamedArg[T]
+ val pos = cpos union arg.pos
}
/** name = arg, outside a parameter list */
- case class Assign[T](lhs: Tree[T], rhs: Tree[T])(implicit val pos: Position)
+ case class Assign[T](lhs: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Assign[T]
+ val pos = cpos union lhs.pos union rhs.pos
}
/** (vparams) => body */
- case class Function[T](vparams: List[ValDef[T]], body: Tree[T])(implicit val pos: Position)
+ case class Function[T](vparams: List[ValDef[T]], body: Tree[T])(implicit cpos: Position)
extends SymTree[T] with TermTree[T] {
type ThisTree[T] = Function[T]
+ val pos = unionPos(cpos union body.pos, vparams)
}
/** { stats; expr } */
- case class Block[T](stats: List[Tree[T]], expr: Tree[T])(implicit val pos: Position)
+ case class Block[T](stats: List[Tree[T]], expr: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Block[T]
+ val pos = unionPos(cpos union expr.pos, stats)
}
/** if cond then thenp else elsep */
- case class If[T](cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit val pos: Position)
+ case class If[T](cond: Tree[T], thenp: Tree[T], elsep: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = If[T]
+ val pos = cpos union cond.pos union thenp.pos union elsep.pos
}
/** selector match { cases } */
- case class Match[T](selector: Tree[T], cases: List[CaseDef[T]])(implicit val pos: Position)
+ case class Match[T](selector: Tree[T], cases: List[CaseDef[T]])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Match[T]
+ val pos = unionPos(cpos union selector.pos, cases)
}
/** case pat if guard => body */
- case class CaseDef[T](pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit val pos: Position)
+ case class CaseDef[T](pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit cpos: Position)
extends Tree[T] {
type ThisTree[T] = CaseDef[T]
+ val pos = cpos union pat.pos union guard.pos union body.pos
}
/** return expr
@@ -247,107 +288,124 @@ object Trees {
* After program transformations this is not necessarily the enclosing method, because
* closures can intervene.
*/
- case class Return[T](expr: Tree[T], from: Ident[T])(implicit val pos: Position)
+ case class Return[T](expr: Tree[T], from: Ident[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Return[T]
+ val pos = cpos union expr.pos // from is synthetic, does not influence pos
}
/** try block catch { catches } */
- case class Try[T](block: Tree[T], catches: List[CaseDef[T]], finalizer: Tree[T])(implicit val pos: Position)
+ case class Try[T](block: Tree[T], catches: List[CaseDef[T]], finalizer: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Try[T]
+ val pos = unionPos(cpos union block.pos union finalizer.pos, catches)
}
/** throw expr */
- case class Throw[T](expr: Tree[T])(implicit val pos: Position)
+ case class Throw[T](expr: Tree[T])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = Throw[T]
+ val pos = cpos union expr.pos
}
/** Array[elemtpt](elems) */
- case class ArrayValue[T](elemtpt: Tree[T], elems: List[Tree[T]])(implicit val pos: Position)
+ case class ArrayValue[T](elemtpt: Tree[T], elems: List[Tree[T]])(implicit cpos: Position)
extends TermTree[T] {
type ThisTree[T] = ArrayValue[T]
+ val pos = unionPos(cpos union elemtpt.pos, elems)
}
/** A type tree that represents an existing or inferred type */
- case class TypeTree[T](original: Tree[T] = EmptyTree[T])(implicit val pos: Position)
+ case class TypeTree[T](original: Tree[T] = EmptyTree[T])(implicit cpos: Position)
extends SymTree[T] with TypTree[T] {
type ThisTree[T] = TypeTree[T]
+ val pos = cpos union original.pos
}
/** ref.type */
- case class SingletonTypeTree[T](ref: Tree[T])(implicit val pos: Position)
+ case class SingletonTypeTree[T](ref: Tree[T])(implicit cpos: Position)
extends SymTree[T] with TypTree[T] {
type ThisTree[T] = SingletonTypeTree[T]
+ val pos = cpos union ref.pos
}
/** qualifier # name */
- case class SelectFromTypeTree[T](qualifier: Tree[T], name: TypeName)(implicit val pos: Position)
+ case class SelectFromTypeTree[T](qualifier: Tree[T], name: TypeName)(implicit cpos: Position)
extends RefTree[T] with TypTree[T] {
type ThisTree[T] = SelectFromTypeTree[T]
+ val pos = cpos union qualifier.pos
}
/** left & right */
- case class AndTypeTree[T](left: Tree[T], right: Tree[T])(implicit val pos: Position)
+ case class AndTypeTree[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TypTree[T] {
type ThisTree[T] = AndTypeTree[T]
+ val pos = cpos union left.pos union right.pos
}
/** left | right */
- case class OrTypeTree[T](left: Tree[T], right: Tree[T])(implicit val pos: Position)
+ case class OrTypeTree[T](left: Tree[T], right: Tree[T])(implicit cpos: Position)
extends TypTree[T] {
type ThisTree[T] = OrTypeTree[T]
+ val pos = cpos union left.pos union right.pos
}
/** tpt { refinements } */
- case class RefineTypeTree[T](tpt: Tree[T], refinements: List[DefTree[T]])(implicit val pos: Position)
+ case class RefineTypeTree[T](tpt: Tree[T], refinements: List[DefTree[T]])(implicit cpos: Position)
extends ProxyTree[T] with TypTree[T] {
type ThisTree[T] = RefineTypeTree[T]
+ val pos = unionPos(cpos union tpt.pos, refinements)
def forwardTo = tpt
}
/** tpt[args] */
- case class AppliedTypeTree[T](tpt: Tree[T], args: List[Tree[T]])(implicit val pos: Position)
+ case class AppliedTypeTree[T](tpt: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends ProxyTree[T] with TypTree[T] {
type ThisTree[T] = AppliedTypeTree[T]
+ val pos = unionPos(cpos union tpt.pos, args)
def forwardTo = tpt
}
/** >: lo <: hi */
- case class TypeBoundsTree[T](lo: Tree[T], hi: Tree[T])(implicit val pos: Position)
+ case class TypeBoundsTree[T](lo: Tree[T], hi: Tree[T])(implicit cpos: Position)
extends Tree[T] {
type ThisTree[T] = TypeBoundsTree[T]
+ val pos = cpos union lo.pos union hi.pos
}
/** name @ body */
- case class Bind[T](name: Name, body: Tree[T])(implicit val pos: Position)
+ case class Bind[T](name: Name, body: Tree[T])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = Bind[T]
+ val pos = cpos union body.pos
}
/** tree_1 | ... | tree_n */
- case class Alternative[T](trees: List[Tree[T]])(implicit val pos: Position)
+ case class Alternative[T](trees: List[Tree[T]])(implicit cpos: Position)
extends Tree[T] {
type ThisTree[T] = Alternative[T]
+ val pos = unionPos(cpos, trees)
}
/** fun(args) in a pattern, if fun is an extractor */
- case class UnApply[T](fun: Tree[T], args: List[Tree[T]])(implicit val pos: Position)
+ case class UnApply[T](fun: Tree[T], args: List[Tree[T]])(implicit cpos: Position)
extends Tree[T] {
type ThisTree[T] = UnApply[T]
+ val pos = unionPos(cpos union fun.pos, args)
}
/** mods val name: tpt = rhs */
- case class ValDef[T](mods: Modifiers[T], name: Name, tpt: Tree[T], rhs: Tree[T])(implicit val pos: Position)
+ case class ValDef[T](mods: Modifiers[T], name: Name, tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = ValDef[T]
+ val pos = cpos union tpt.pos union rhs.pos
}
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
- case class DefDef[T](mods: Modifiers[T], name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit val pos: Position)
+ case class DefDef[T](mods: Modifiers[T], name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = DefDef[T]
+ val pos = (unionPos(cpos union tpt.pos union rhs.pos, tparams) /: vparamss)(unionPos)
}
class ImplicitDefDef[T](mods: Modifiers[T], name: Name, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])
@@ -358,43 +416,49 @@ object Trees {
/** mods type name = rhs or
* mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) */
- case class TypeDef[T](mods: Modifiers[T], name: Name, rhs: Tree[T])(implicit val pos: Position)
+ case class TypeDef[T](mods: Modifiers[T], name: Name, rhs: Tree[T])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = TypeDef[T]
+ val pos = cpos union rhs.pos
}
/** extends parents { self => body } */
- case class Template[T](parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]])(implicit val pos: Position)
+ case class Template[T](parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]])(implicit cpos: Position)
extends SymTree[T] {
type ThisTree[T] = Template[T]
+ val pos = unionPos(unionPos(cpos union self.pos, parents), body)
}
/** mods class name[tparams] impl */
- case class ClassDef[T](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])(implicit val pos: Position)
+ case class ClassDef[T](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = ClassDef[T]
+ val pos = unionPos(cpos union impl.pos, tparams)
}
/** import expr.selectors
* where a selector is either an untyped `Ident`, `name` or
* an untyped `Pair` `name => rename`
*/
- case class Import[T](expr: Tree[T], selectors: List[UntypedTree])(implicit val pos: Position)
+ case class Import[T](expr: Tree[T], selectors: List[UntypedTree])(implicit cpos: Position)
extends SymTree[T] {
type ThisTree[T] = Import[T]
+ val pos = unionPos(cpos union expr.pos, selectors)
}
/** package pid { stats } */
- case class PackageDef[T](pid: RefTree[T], stats: List[Tree[T]])(implicit val pos: Position)
+ case class PackageDef[T](pid: RefTree[T], stats: List[Tree[T]])(implicit cpos: Position)
extends DefTree[T] {
type ThisTree[T] = PackageDef[T]
+ val pos = unionPos(cpos union pid.pos, stats)
override def name = pid.name
}
/** arg @annot */
- case class Annotated[T](annot: Tree[T], arg: Tree[T])(implicit val pos: Position)
+ case class Annotated[T](annot: Tree[T], arg: Tree[T])(implicit cpos: Position)
extends ProxyTree[T] {
type ThisTree[T] = Annotated[T]
+ val pos = cpos union annot.pos union arg.pos
def forwardTo = arg
}
@@ -426,20 +490,34 @@ object Trees {
def apply[T]: EmptyValDef[T] = theEmptyValDef.asInstanceOf
}
-// ----- Tree cases that exist in untyped form only ------------------
+ /** A tree that can be shared without its position polluting containing trees */
+ case class Shared[T](tree: Tree[T]) extends Tree[T] {
+ type ThisTree[T] = Shared[T]
+ val pos = NoPosition
+ }
+
+ // ----- Tree cases that exist in untyped form only ------------------
/** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */
- case class TypedSplice(tree: TypedTree) extends UntypedTree {
- def pos = tree.pos
+ class TypedSplice(tree: TypedTree) extends UntypedTree {
+ val pos = tree.pos
}
/** mods object name impl */
- case class ModuleDef(mods: Modifiers[Nothing], name: TermName, impl: Template[Nothing])(implicit val pos: Position)
+ case class ModuleDef(mods: Modifiers[Nothing], name: TermName, impl: Template[Nothing])(implicit cpos: Position)
extends DefTree[Nothing] {
+ val pos = cpos union impl.pos
}
abstract class TreeAccumulator[T, U] extends ((T, Tree[U]) => T) {
def apply(x: T, tree: Tree[U]): T
def foldOver(x: T, tree: Tree[U]): T = ???
}
+
+// ----- Helper functions ---------------------------------------------
+
+ @tailrec final def unionPos(base: Position, trees: List[Tree[_]]): Position = trees match {
+ case t :: ts => unionPos(base union t.pos, ts)
+ case nil => base
+ }
} \ No newline at end of file