The direct child trees of this tree.
The direct child trees of this tree. EmptyTrees are always omitted. Lists are flattened.
Like setType
, but if this is a previously empty TypeTree that
fact is remembered so that resetAllAttrs will snap back.
Like setType
, but if this is a previously empty TypeTree that
fact is remembered so that resetAllAttrs will snap back.
Attempting to elaborate on the above, I find: If defineType is called on a TypeTree whose type field is null or NoType, this is recorded as "wasEmpty = true". That value is used in ResetAttrsTraverser, which nulls out the type field of TypeTrees for which wasEmpty is true, leaving the others alone.
resetAllAttrs is used in situations where some speculative
typing of a tree takes place, fails, and the tree needs to be
returned to its former state to try again. So according to me:
using defineType
instead of setType
is how you communicate
that the type being set does not depend on any previous state,
and therefore should be abandoned if the current line of type
inquiry doesn't work out.
Is there part of this tree which satisfies predicate p
?
Find all subtrees matching predicate p
Returns optionally first tree (in a preorder traversal) which satisfies predicate p
,
or None if none exists.
Apply f
to each subtree
The canonical way to test if a Tree represents a term.
The canonical way to test if a Tree represents a type.
Set tpe to give tp
and return this.
Note that symbol is fixed as null at this level.
Note that symbol is fixed as null at this level. In SymTrees, it is overridden and implemented with a var, initialized to NoSymbol.
Trees which are not SymTrees but which carry symbols do so by
overriding def symbol
to forward it elsewhere. Examples:
Super(qual, _) // has qual's symbol Apply(fun, args) // has fun's symbol TypeApply(fun, args) // has fun's symbol AppliedTypeTree(tpt, args) // has tpt's symbol TypeTree(tpe) // has tpe's typeSymbol, if tpe != null
Attempting to set the symbol of a Tree which does not support it will induce an exception.
Tree is the basis for scala's abstract syntax. The nodes are implemented as case classes, and the parameters which initialize a given tree are immutable: however Trees have several mutable fields which are manipulated in the course of typechecking, including pos, symbol, and tpe.
Newly instantiated trees have tpe set to null (though it may be set immediately thereafter depending on how it is constructed.) When a tree is passed to the typer, typically via
typer.typed(tree)
, under normal circumstances the tpe must be null or the typer will ignore it. Furthermore, the typer is not required to return the same tree it was passed.Trees can be easily traversed with e.g. foreach on the root node; for a more nuanced traversal, subclass Traverser. Transformations can be considerably trickier: see the numerous subclasses of Transformer found around the compiler.
Copying Trees should be done with care depending on whether it need be done lazily or strictly (see LazyTreeCopier and StrictTreeCopier) and on whether the contents of the mutable fields should be copied. The tree copiers will copy the mutable attributes to the new tree; calling Tree#duplicate will copy symbol and tpe, but all the positions will be focused.
Trees can be coarsely divided into four mutually exclusive categories:
TypTree
, notTypeTree
.SymTrees include important nodes Ident and Select, which are used as both terms and types; they are distinguishable based on whether the Name is a TermName or TypeName. The correct way for to test for a type or a term (on any Tree) are the isTerm/isType methods on Tree.
"Others" are mostly syntactic or short-lived constructs. Examples include CaseDef, which wraps individual match cases: they are neither terms nor types, nor do they carry a symbol. Another example is Parens, which is eliminated during parsing.