Skip to content
Browse files

DummyTree => CannotHaveAttrs

This looks like a much more specific name than a generic "dummy" prefix.
CannotHaveAttrs also doesn't imply that an implementing tree should
satisfy some bigger contract. EmptyTree and emptyValDef are very unlike
each other, so there's no point in trying to unify them.

Also DummyTree.isEmpty is no longer automatically true. The notion of
trees not having positions and types by design (i.e. EmptyTree + empty
TypeTrees + emptyValDef + the new pendingSuperCall) is quite different
from the notion of an empty tree in a sense of a tree being a null object
(i.e. EmptyTree + empty TypeTrees).
  • Loading branch information...
1 parent 7ee299b commit 838cbe623c142b7005446793948097f679219fe3 @xeno-by xeno-by committed Dec 4, 2012
View
2 src/compiler/scala/tools/nsc/ast/Positions.scala
@@ -20,7 +20,7 @@ trait Positions extends scala.reflect.internal.Positions {
// When we prune due to encountering a position, traverse the
// pruned children so we can warn about those lacking positions.
t.children foreach { c =>
- if (c.isDummy) ()
+ if (!c.canHaveAttrs) ()
else if (c.pos == NoPosition) {
reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase)
inform("parent: " + treeSymStatus(t))
View
2 src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -337,7 +337,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
else
super.transform {
tree match {
- case tree if tree.isDummy =>
+ case tree if !tree.canHaveAttrs =>
tree
case tpt: TypeTree =>
if (tpt.original != null)
View
2 src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2767,7 +2767,7 @@ self =>
if (in.token == LBRACE) {
// @S: pre template body cannot stub like post body can!
val (self, body) = templateBody(isPre = true)
- if (in.token == WITH && self.isEmpty) {
+ if (in.token == WITH && (self eq emptyValDef)) {
val earlyDefs: List[Tree] = body flatMap {
case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred =>
List(copyValDef(vdef)(mods = mods | Flags.PRESUPER))
View
6 src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -144,7 +144,7 @@ self: scala.tools.nsc.Global =>
*/
private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
for (tree <- trees) {
- if (!tree.isEmpty && tree.pos == NoPosition) {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
val children = tree.children
if (children.isEmpty) {
tree setPos pos.focus
@@ -165,7 +165,7 @@ self: scala.tools.nsc.Global =>
*/
override def atPos[T <: Tree](pos: Position)(tree: T): T = {
if (pos.isOpaqueRange) {
- if (!tree.isEmpty && tree.pos == NoPosition) {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
tree.setPos(pos)
val children = tree.children
if (children.nonEmpty) {
@@ -203,7 +203,7 @@ self: scala.tools.nsc.Global =>
def validate(tree: Tree, encltree: Tree): Unit = {
- if (!tree.isEmpty) {
+ if (!tree.isEmpty && tree.canHaveAttrs) {
if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value))
println("[%10s] %s".format("validate", treeStatus(tree, encltree)))
View
2 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -52,7 +52,7 @@ trait Typers extends Modes with Adaptations with Tags {
object UnTyper extends Traverser {
override def traverse(tree: Tree) = {
- if (!tree.isDummy) {
+ if (tree.canHaveAttrs) {
tree.tpe = null
if (tree.hasSymbol) tree.symbol = NoSymbol
}
View
18 src/reflect/scala/reflect/api/Trees.scala
@@ -75,11 +75,26 @@ trait Trees { self: Universe =>
def isDef: Boolean
/** Is this tree one of the empty trees?
+ *
* Empty trees are: the `EmptyTree` null object, `TypeTree` instances that don't carry a type
* and the special `emptyValDef` singleton.
+ *
+ * In the compiler the `isEmpty` check and the derived `orElse` method are mostly used
+ * as a check for a tree being a null object (`EmptyTree` for term trees and empty TypeTree for type trees).
+ *
+ * Unfortunately `emptyValDef` is also considered to be `isEmpty`, but this is deemed to be
+ * a conceptual mistake pending a fix in https://issues.scala-lang.org/browse/SI-6762.
+ *
+ * @see `canHaveAttrs`
*/
def isEmpty: Boolean
+ /** Can this tree carry attributes (i.e. symbols, types or positions)?
+ * Typically the answer is yes, except for the `EmptyTree` null object and
+ * two special singletons: `emptyValDef` and `pendingSuperCall`.
+ */
+ def canHaveAttrs: Boolean
+
/** The canonical way to test if a Tree represents a term.
*/
def isTerm: Boolean
@@ -2852,7 +2867,8 @@ trait Trees { self: Universe =>
trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef])
/** Transforms a `ValDef`. */
def transformValDef(tree: ValDef): ValDef =
- if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef]
+ if (tree eq emptyValDef) tree
+ else transform(tree).asInstanceOf[ValDef]
/** Transforms a list of `ValDef` nodes. */
def transformValDefs(trees: List[ValDef]): List[ValDef] =
trees mapConserve (transformValDef(_))
View
2 src/reflect/scala/reflect/internal/Positions.scala
@@ -38,7 +38,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
protected class DefaultPosAssigner extends PosAssigner {
var pos: Position = _
override def traverse(t: Tree) {
- if (t.isDummy) ()
+ if (!t.canHaveAttrs) ()
else if (t.pos == NoPosition) {
t.setPos(pos)
super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
View
2 src/reflect/scala/reflect/internal/Printers.scala
@@ -435,7 +435,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case tree =>
xprintTree(this, tree)
}
- if (printTypes && tree.isTerm && !tree.isEmpty) {
+ if (printTypes && tree.isTerm && tree.canHaveAttrs) {
print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
}
}
View
15 src/reflect/scala/reflect/internal/Trees.scala
@@ -36,7 +36,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def isDef = false
def isEmpty = false
- def isDummy = false
+ def canHaveAttrs = true
/** The canonical way to test if a Tree represents a term.
*/
@@ -955,9 +955,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree)
- trait DummyTree extends Tree {
- override def isEmpty = true
- override def isDummy = true
+ trait CannotHaveAttrs extends Tree {
+ override def canHaveAttrs = false
private def unsupported(what: String, args: Any*) =
throw new UnsupportedOperationException(s"$what($args) inapplicable for "+self.toString)
@@ -969,9 +968,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def tpe_=(t: Type) = if (t != NoType) unsupported("tpe_=", t)
}
- case object EmptyTree extends TermTree with DummyTree { val asList = List(this) }
- object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with DummyTree
- object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with DummyTree
+ case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) }
+ object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with CannotHaveAttrs
+ object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with CannotHaveAttrs
def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef =
atPos(sym.pos) {
@@ -1123,7 +1122,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
traverse(annot); traverse(arg)
case Template(parents, self, body) =>
traverseTrees(parents)
- if (!self.isEmpty) traverse(self)
+ if (self ne emptyValDef) traverse(self)
traverseStats(body, tree.symbol)
case Block(stats, expr) =>
traverseTrees(stats); traverse(expr)

0 comments on commit 838cbe6

Please sign in to comment.
Something went wrong with that request. Please try again.