Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

388 lines (339 sloc) 16.728 kB
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package ast
import scala.reflect.internal.Flags.BYNAMEPARAM
import scala.reflect.internal.Flags.DEFAULTPARAM
import scala.reflect.internal.Flags.IMPLICIT
import scala.reflect.internal.Flags.PARAM
import scala.reflect.internal.Flags.PARAMACCESSOR
import scala.reflect.internal.Flags.PRESUPER
import scala.reflect.internal.Flags.TRAIT
import scala.compat.Platform.EOL
trait Trees extends scala.reflect.internal.Trees { self: Global =>
def treeLine(t: Tree): String =
if (t.pos.isDefined && t.pos.isRange) t.pos.lineContent.drop(t.pos.column - 1).take(t.pos.end - t.pos.start + 1)
else t.summaryString
def treeStatus(t: Tree, enclosingTree: Tree = null) = {
val parent = if (enclosingTree eq null) " " else " P#%5s".format(enclosingTree.id)
"[L%4s%8s] #%-6s %-15s %-10s // %s".format(t.pos.safeLine, parent, t.id, t.pos.show, t.shortClass, treeLine(t))
}
def treeSymStatus(t: Tree) = {
val line = if (t.pos.isDefined) "line %-4s".format(t.pos.safeLine) else " "
"#%-5s %s %-10s // %s".format(t.id, line, t.shortClass,
if (t.symbol ne NoSymbol) "(" + t.symbol.fullLocationString + ")"
else treeLine(t)
)
}
// --- additional cases --------------------------------------------------------
/** Only used during parsing */
case class Parens(args: List[Tree]) extends Tree
/** Documented definition, eliminated by analyzer */
case class DocDef(comment: DocComment, definition: Tree)
extends Tree {
override def symbol: Symbol = definition.symbol
override def symbol_=(sym: Symbol) { definition.symbol = sym }
override def isDef = definition.isDef
override def isTerm = definition.isTerm
override def isType = definition.isType
}
/** Array selection `<qualifier> . <name>` only used during erasure */
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
extends RefTree with TermTree
/** Derived value class injection (equivalent to: `new C(arg)` after erasure); only used during erasure.
* The class `C` is stored as a tree attachment.
*/
case class InjectDerivedValue(arg: Tree)
extends SymTree with TermTree
class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name)
/** emitted by typer, eliminated by refchecks */
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
// --- factory methods ----------------------------------------------------------
/** Factory method for a primary constructor super call `super.<init>(args_1)...(args_n)`
*/
def PrimarySuperCall(argss: List[List[Tree]]): Tree = argss match {
case Nil => Apply(gen.mkSuperInitCall, Nil)
case xs :: rest => rest.foldLeft(Apply(gen.mkSuperInitCall, xs): Tree)(Apply.apply)
}
/** Generates a template with constructor corresponding to
*
* constrmods (vparams1_) ... (vparams_n) preSuper { presupers }
* extends superclass(args_1) ... (args_n) with mixins { self => body }
*
* This gets translated to
*
* extends superclass with mixins { self =>
* presupers' // presupers without rhs
* vparamss // abstract fields corresponding to value parameters
* def <init>(vparamss) {
* presupers
* super.<init>(args)
* }
* body
* }
*/
def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): Template = {
/* Add constructor to template */
// create parameters for <init> as synthetic trees.
var vparamss1 = mmap(vparamss) { vd =>
atPos(vd.pos.focus) {
val mods = Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR)
ValDef(mods withAnnotations vd.mods.annotations, vd.name, vd.tpt.duplicate, vd.rhs.duplicate)
}
}
val (edefs, rest) = body span treeInfo.isEarlyDef
val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef
val gvdefs = evdefs map {
case vdef @ ValDef(_, _, tpt, _) =>
copyValDef(vdef)(
// atPos for the new tpt is necessary, since the original tpt might have no position
// (when missing type annotation for ValDef for example), so even though setOriginal modifies the
// position of TypeTree, it would still be NoPosition. That's what the author meant.
tpt = atPos(vdef.pos.focus)(TypeTree() setOriginal tpt setPos tpt.pos.focus),
rhs = EmptyTree
)
}
val lvdefs = evdefs collect { case vdef: ValDef => copyValDef(vdef)(mods = vdef.mods | PRESUPER) }
val constrs = {
if (constrMods hasFlag TRAIT) {
if (body forall treeInfo.isInterfaceMember) List()
else List(
atPos(wrappingPos(superPos, lvdefs)) (
DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), ListOfNil, TypeTree(), Block(lvdefs, Literal(Constant())))))
} else {
// convert (implicit ... ) to ()(implicit ... ) if its the only parameter section
if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit)
vparamss1 = List() :: vparamss1;
val superRef: Tree = atPos(superPos)(gen.mkSuperInitCall)
val superCall = pendingSuperCall // we can't know in advance which of the parents will end up as a superclass
// this requires knowing which of the parents is a type macro and which is not
// and that's something that cannot be found out before typer
// (the type macros aren't in the trunk yet, but there is a plan for them to land there soon)
// this means that we don't know what will be the arguments of the super call
// therefore here we emit a dummy which gets populated when the template is named and typechecked
List(
// TODO: previously this was `wrappingPos(superPos, lvdefs ::: argss.flatten)`
// is it going to be a problem that we can no longer include the `argss`?
atPos(wrappingPos(superPos, lvdefs)) (
DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant())))))
}
}
constrs foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus=false))
// Field definitions for the class - remove defaults.
val fieldDefs = vparamss.flatten map (vd => copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree))
Template(parents, self, gvdefs ::: fieldDefs ::: constrs ::: etdefs ::: rest)
}
/** Construct class definition with given class symbol, value parameters,
* supercall arguments and template body.
*
* @param sym the class symbol
* @param constrMods the modifiers for the class constructor, i.e. as in `class C private (...)`
* @param vparamss the value parameters -- if they have symbols they
* should be owned by `sym`
* @param body the template statements without primary constructor
* and value parameter fields.
*/
def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): ClassDef = {
// "if they have symbols they should be owned by `sym`"
assert(
mforall(vparamss)(p => (p.symbol eq NoSymbol) || (p.symbol.owner == sym)),
((mmap(vparamss)(_.symbol), sym))
)
ClassDef(sym,
Template(sym.info.parents map TypeTree,
if (sym.thisSym == sym || phase.erasedTypes) emptyValDef else ValDef(sym.thisSym),
constrMods, vparamss, body, superPos))
}
// --- subcomponents --------------------------------------------------
object treeInfo extends {
val global: Trees.this.type = self
} with TreeInfo
lazy val treePrinter = newTreePrinter()
// --- additional cases in operations ----------------------------------
override protected def xtraverse(traverser: Traverser, tree: Tree): Unit = tree match {
case Parens(ts) =>
traverser.traverseTrees(ts)
case DocDef(comment, definition) =>
traverser.traverse(definition)
case SelectFromArray(qualifier, selector, erasure) =>
traverser.traverse(qualifier)
case InjectDerivedValue(arg) =>
traverser.traverse(arg)
case TypeTreeWithDeferredRefCheck() =>
// (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
case _ => super.xtraverse(traverser, tree)
}
trait TreeCopier extends super.InternalTreeCopierOps {
def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray
def InjectDerivedValue(tree: Tree, arg: Tree): InjectDerivedValue
def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck
}
def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
def newLazyTreeCopier: TreeCopier = new LazyTreeCopier
class StrictTreeCopier extends super.StrictTreeCopier with TreeCopier {
def DocDef(tree: Tree, comment: DocComment, definition: Tree) =
new DocDef(comment, definition).copyAttrs(tree)
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) =
new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree)
def InjectDerivedValue(tree: Tree, arg: Tree) =
new InjectDerivedValue(arg).copyAttrs(tree)
def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree)
}
}
class LazyTreeCopier extends super.LazyTreeCopier with TreeCopier {
def DocDef(tree: Tree, comment: DocComment, definition: Tree) = tree match {
case t @ DocDef(comment0, definition0)
if (comment0 == comment) && (definition0 == definition) => t
case _ => this.treeCopy.DocDef(tree, comment, definition)
}
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = tree match {
case t @ SelectFromArray(qualifier0, selector0, _)
if (qualifier0 == qualifier) && (selector0 == selector) => t
case _ => this.treeCopy.SelectFromArray(tree, qualifier, selector, erasure)
}
def InjectDerivedValue(tree: Tree, arg: Tree) = tree match {
case t @ InjectDerivedValue(arg0)
if (arg0 == arg) => t
case _ => this.treeCopy.InjectDerivedValue(tree, arg)
}
def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
case t @ TypeTreeWithDeferredRefCheck() => t
case _ => this.treeCopy.TypeTreeWithDeferredRefCheck(tree)
}
}
class Transformer extends super.Transformer {
def transformUnit(unit: CompilationUnit) {
try unit.body = transform(unit.body)
catch {
case ex: Exception =>
println(supplementErrorMessage("unhandled exception while transforming "+unit))
throw ex
}
}
}
// used when a phase is disabled
object noopTransformer extends Transformer {
override def transformUnit(unit: CompilationUnit): Unit = {}
}
override protected def xtransform(transformer: super.Transformer, tree: Tree): Tree = tree match {
case DocDef(comment, definition) =>
transformer.treeCopy.DocDef(tree, comment, transformer.transform(definition))
case SelectFromArray(qualifier, selector, erasure) =>
transformer.treeCopy.SelectFromArray(
tree, transformer.transform(qualifier), selector, erasure)
case InjectDerivedValue(arg) =>
transformer.treeCopy.InjectDerivedValue(
tree, transformer.transform(arg))
case TypeTreeWithDeferredRefCheck() =>
transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree)
}
object resetPos extends Traverser {
override def traverse(t: Tree) {
if (t != EmptyTree) t.setPos(NoPosition)
super.traverse(t)
}
}
/** resets symbol and tpe fields in a tree, @see ResetAttrs
*/
// def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x }
// def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x }
def resetAllAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(false, leaveAlone).transform(x)
def resetLocalAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(true, leaveAlone).transform(x)
def resetLocalAttrsKeepLabels(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(true, leaveAlone, true).transform(x)
/** A transformer which resets symbol and tpe fields of all nodes in a given tree,
* with special treatment of:
* TypeTree nodes: are replaced by their original if it exists, otherwise tpe field is reset
* to empty if it started out empty or refers to local symbols (which are erased).
* TypeApply nodes: are deleted if type arguments end up reverted to empty
* This(pkg) nodes where pkg is a package: these are kept.
*
* (bq:) This transformer has mutable state and should be discarded after use
*/
private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null, keepLabels: Boolean = false) {
val debug = settings.debug.value
val trace = scala.tools.nsc.util.trace when debug
val locals = util.HashSet[Symbol](8)
val orderedLocals = scala.collection.mutable.ListBuffer[Symbol]()
def registerLocal(sym: Symbol) {
if (sym != null && sym != NoSymbol) {
if (debug && !(locals contains sym)) orderedLocals append sym
locals addEntry sym
}
}
class MarkLocals extends self.Traverser {
def markLocal(tree: Tree) {
if (tree.symbol != null && tree.symbol != NoSymbol) {
val sym = tree.symbol
registerLocal(sym)
registerLocal(sym.sourceModule)
registerLocal(sym.moduleClass)
registerLocal(sym.companionClass)
registerLocal(sym.companionModule)
sym match {
case sym: TermSymbol => registerLocal(sym.referenced)
case _ => ;
}
}
}
override def traverse(tree: Tree) = {
tree match {
case _: DefTree | Function(_, _) | Template(_, _, _) =>
markLocal(tree)
case _ =>
tree
}
super.traverse(tree)
}
}
class Transformer extends self.Transformer {
override def transform(tree: Tree): Tree = {
if (leaveAlone != null && leaveAlone(tree))
tree
else
super.transform {
tree match {
case tree if !tree.canHaveAttrs =>
tree
case tpt: TypeTree =>
if (tpt.original != null)
transform(tpt.original)
else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => locals contains tp.typeSymbol)))) {
tpt.duplicate.clearType()
}
else tree
case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
transform(fn)
case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
tree
case _ =>
val dupl = tree.duplicate
if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel))
dupl.symbol = NoSymbol
dupl.clearType()
}
}
}
}
def transform(x: Tree): Tree = {
if (localOnly)
new MarkLocals().traverse(x)
if (localOnly && debug) {
assert(locals.size == orderedLocals.size)
val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString EOL
trace("locals (%d total): %n".format(orderedLocals.size))(msg)
}
new Transformer().transform(x)
}
}
/* New pattern matching cases:
case Parens(expr) (only used during parsing)
case DocDef(comment, defn) => (eliminated by typer)
case TypeTreeWithDeferredRefCheck() => (created and eliminated by typer)
case SelectFromArray(_, _, _) => (created and eliminated by erasure)
case InjectDerivedValue(_) => (created and eliminated by erasure)
*/
}
Jump to Line
Something went wrong with that request. Please try again.