From d5006b118f6ad1bf10ed35491cd0bda05fc88972 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 23 Feb 2012 00:36:18 -0800 Subject: Methods to derive ValDefs and Templates. It's a lot like the last one. I also found trees being duplicated before being sent to the tree copier. Looks like xerox has gotten a mole in here. Trust no one. --- src/compiler/scala/reflect/internal/Trees.scala | 13 +++++++++- src/compiler/scala/tools/nsc/ast/Trees.scala | 28 ++++++++++----------- .../scala/tools/nsc/javac/JavaParsers.scala | 5 +--- .../scala/tools/nsc/transform/Constructors.scala | 7 +++--- .../scala/tools/nsc/transform/ExplicitOuter.scala | 6 +++-- .../scala/tools/nsc/transform/LambdaLift.scala | 14 +++++------ .../scala/tools/nsc/transform/LazyVals.scala | 17 +++++++------ .../tools/nsc/transform/SpecializeTypes.scala | 13 +++++----- .../scala/tools/nsc/transform/UnCurry.scala | 10 +++----- .../tools/nsc/typechecker/MethodSynthesis.scala | 2 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 3 +-- .../tools/nsc/typechecker/SuperAccessors.scala | 4 +-- .../tools/nsc/typechecker/SyntheticMethods.scala | 6 ++--- .../scala/tools/nsc/typechecker/Typers.scala | 4 +-- src/library/scala/reflect/api/Trees.scala | 29 ++++++++++++++++++++++ 15 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index b6b7e3cbda..610c6dc493 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -272,7 +272,18 @@ trait Trees extends api.Trees { self: SymbolTable => override def traverse(t: Tree) { if (t != EmptyTree && t.pos == NoPosition) { t.setPos(pos) - super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if? + super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if? + // @PP: it's pruning whenever it encounters a node with a + // position, which I interpret to mean that (in the author's + // mind at least) either the children of a positioned node will + // already be positioned, or the children of a positioned node + // do not merit positioning. + // + // Whatever the author's rationale, it does seem like a bad idea + // to press on through a positioned node to find unpositioned + // children beneath it and then to assign whatever happens to + // be in `pos` to such nodes. There are supposed to be some + // position invariants which I can't imagine surviving that. } } } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 855b55bb5e..ad87889145 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -79,16 +79,16 @@ trait Trees extends reflect.internal.Trees { self: Global => val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val gvdefs = evdefs map { - case vdef @ ValDef(mods, name, tpt, rhs) => - treeCopy.ValDef( - vdef.duplicate, mods, name, - atPos(focusPos(vdef.pos)) { TypeTree() setOriginal tpt setPos focusPos(tpt.pos) }, // atPos in case - EmptyTree) - } - val lvdefs = evdefs map { - case vdef @ ValDef(mods, name, tpt, rhs) => - treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) + case vdef @ ValDef(_, _, tpt, _) => copyValDef(vdef)( + // !!! I know "atPos in case" wasn't intentionally planted to + // add an air of mystery to this file, but it is the sort of + // comment which only its author could love. + tpt = atPos(focusPos(vdef.pos))(TypeTree() setOriginal tpt setPos focusPos(tpt.pos)), // atPos in case + rhs = EmptyTree + ) } + val lvdefs = evdefs collect { case vdef: ValDef => copyValDef(vdef)(mods = Modifiers(PRESUPER)) } + val constrs = { if (constrMods hasFlag TRAIT) { if (body forall treeInfo.isInterfaceMember) List() @@ -108,13 +108,11 @@ trait Trees extends reflect.internal.Trees { self: Global => DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant()))))) } } - // println("typed template, gvdefs = "+gvdefs+", parents = "+parents+", constrs = "+constrs) constrs foreach (ensureNonOverlapping(_, parents ::: gvdefs)) - // vparamss2 are used as field definitions for the class. remove defaults - val vparamss2 = vparamss map (vps => vps map { vd => - treeCopy.ValDef(vd, vd.mods &~ DEFAULTPARAM, vd.name, vd.tpt, EmptyTree) - }) - Template(parents, self, gvdefs ::: vparamss2.flatten ::: constrs ::: etdefs ::: rest) + // 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, diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 3490c1f5a8..62f6c90fba 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -653,10 +653,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { // leaves auxiliary constructors unable to access members of the companion object // as unqualified identifiers. def addCompanionObject(statics: List[Tree], cdef: ClassDef): List[Tree] = { - def implWithImport(importStmt: Tree) = { - import cdef.impl._ - treeCopy.Template(cdef.impl, parents, self, importStmt :: body) - } + def implWithImport(importStmt: Tree) = deriveTemplate(cdef.impl)(importStmt :: _) // if there are no statics we can use the original cdef, but we always // create the companion so import A._ is not an error (see ticket #1700) val cdefNew = diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index c638d25114..bbcf93114c 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -175,7 +175,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { else if (stat.symbol.isConstructor) auxConstructorBuf += stat else defBuf += stat } - case ValDef(mods, name, tpt, rhs) => + case ValDef(_, _, _, rhs) => // val defs with constant right-hand sides are eliminated. // for all other val defs, an empty valdef goes into the template and // the initializer goes as an assignment into the constructor @@ -188,7 +188,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { (if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign( stat.symbol, rhs1) } - defBuf += treeCopy.ValDef(stat, mods, name, tpt, EmptyTree) + defBuf += deriveValDef(stat)(_ => EmptyTree) } case ClassDef(_, _, _, _) => // classes are treated recursively, and left in the template @@ -560,8 +560,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { clazz.info.decls unlink sym // Eliminate all field definitions that can be dropped from template - treeCopy.Template(impl, impl.parents, impl.self, - defBuf.toList filter (stat => mustbeKept(stat.symbol))) + deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustbeKept(stat.symbol))) } // transformClassTemplate override def transform(tree: Tree): Tree = diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index bc35084a4c..86acf3f3c2 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -468,8 +468,10 @@ abstract class ExplicitOuter extends InfoTransform } } super.transform( - treeCopy.Template(tree, parents, self, - if (newDefs.isEmpty) decls else decls ::: newDefs.toList) + deriveTemplate(tree)(decls => + if (newDefs.isEmpty) decls + else decls ::: newDefs.toList + ) ) case DefDef(_, _, _, vparamss, _, rhs) => if (sym.isClassConstructor) { diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 99cc7393aa..50a75f896b 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -326,7 +326,7 @@ abstract class LambdaLift extends InfoTransform { lifted(MethodType(sym.info.params ::: addParams, sym.info.resultType))) copyDefDef(tree)(vparamss = List(vparams ++ freeParams)) - case ClassDef(mods, name, tparams, impl @ Template(parents, self, body)) => + case ClassDef(mods, name, tparams, impl) => // Disabled attempt to to add getters to freeParams // this does not work yet. Problem is that local symbols need local names // and references to local symbols need to be transformed into @@ -338,8 +338,7 @@ abstract class LambdaLift extends InfoTransform { // DefDef(getter, rhs) setPos tree.pos setType NoType // } // val newDefs = if (sym.isTrait) freeParams ::: (ps map paramGetter) else freeParams - treeCopy.ClassDef(tree, mods, name, tparams, - treeCopy.Template(impl, parents, self, body ::: freeParams)) + treeCopy.ClassDef(tree, mods, name, tparams, deriveTemplate(impl)(_ ::: freeParams)) } case None => tree @@ -481,15 +480,14 @@ abstract class LambdaLift extends InfoTransform { /** Transform statements and add lifted definitions to them. */ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { - case ClassDef(mods, name, tparams, impl @ Template(parents, self, body)) => + case ClassDef(mods, name, tparams, impl) => val lifted = liftedDefs get stat.symbol match { case Some(xs) => xs reverseMap addLifted case _ => log("unexpectedly no lifted defs for " + stat.symbol) ; Nil } - val result = treeCopy.ClassDef( - stat, mods, name, tparams, treeCopy.Template(impl, parents, self, body ::: lifted)) - liftedDefs -= stat.symbol - result + try treeCopy.ClassDef(stat, mods, name, tparams, deriveTemplate(impl)(_ ::: lifted)) + finally liftedDefs -= stat.symbol + case DefDef(_, _, _, _, _, Block(Nil, expr)) if !stat.symbol.isConstructor => deriveDefDef(stat)(_ => expr) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 38dfcd4307..28bb2f3501 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -93,7 +93,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD deriveDefDef(tree)(_ => if (LocalLazyValFinder.find(res)) typed(addBitmapDefs(sym, res)) else res) } - case Template(parents, self, body) => atOwner(currentOwner) { + case Template(_, _, body) => atOwner(currentOwner) { val body1 = super.transformTrees(body) var added = false val stats = @@ -105,8 +105,8 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD added = true typed(addBitmapDefs(sym, stat)) } else stat - case ValDef(mods, name, tpt, rhs) => - typed(treeCopy.ValDef(stat, mods, name, tpt, addBitmapDefs(stat.symbol, rhs))) + case ValDef(_, _, _, _) => + typed(deriveValDef(stat)(addBitmapDefs(stat.symbol, _))) case _ => stat } @@ -121,13 +121,14 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD }) toAdd0 } else List() - treeCopy.Template(tree, parents, self, innerClassBitmaps ++ stats) + deriveTemplate(tree)(_ => innerClassBitmaps ++ stats) } - case ValDef(mods, name, tpt, rhs0) if (!sym.owner.isModule && !sym.owner.isClass) => - val rhs = super.transform(rhs0) - treeCopy.ValDef(tree, mods, name, tpt, - if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs) + case ValDef(_, _, _, _) if !sym.owner.isModule && !sym.owner.isClass => + deriveValDef(tree) { rhs0 => + val rhs = super.transform(rhs0) + if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs + } case l@LabelDef(name0, params0, ifp0@If(_, _, _)) if name0.startsWith(nme.WHILE_PREFIX) => val ifp1 = super.transform(ifp0) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 1e1c9efebb..9f40c10db9 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -1480,21 +1480,22 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { localTyper.typed(deriveDefDef(tree)(rhs => rhs)) } - case ValDef(mods, name, tpt, rhs) if symbol.hasFlag(SPECIALIZED) && !symbol.isParamAccessor => + case ValDef(_, _, _, _) if symbol.hasFlag(SPECIALIZED) && !symbol.isParamAccessor => assert(body.isDefinedAt(symbol.alias), body) - val tree1 = treeCopy.ValDef(tree, mods, name, tpt, body(symbol.alias).duplicate) + val tree1 = deriveValDef(tree)(_ => body(symbol.alias).duplicate) debuglog("now typing: " + tree1 + " in " + tree.symbol.owner.fullName) + val d = new Duplicator - val ValDef(mods1, name1, tpt1, rhs1) = d.retyped( + val newValDef = d.retyped( localTyper.context1.asInstanceOf[d.Context], tree1, symbol.alias.enclClass, symbol.enclClass, typeEnv(symbol.alias) ++ typeEnv(tree.symbol) ) - val t = treeCopy.ValDef(tree1, mods1, name1, tpt1, transform(rhs1)) - log("valdef " + tree + " -> " + t) - t + logResult("valdef " + tree + " -> ") { + deriveValDef(newValDef)(transform) + } // val tree1 = // treeCopy.ValDef(tree, mods, name, tpt, diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 4b587a3f41..23673c2a1d 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -620,13 +620,11 @@ abstract class UnCurry extends InfoTransform * In particular, this case will add: * - synthetic Java varargs forwarders for repeated parameters */ - case Template(parents, self, body) => + case Template(_, _, _) => localTyper = typer.atOwner(tree, currentClass) - val tmpl = if (!forMSIL || forMSIL) { - treeCopy.Template(tree, parents, self, transformTrees(newMembers.toList) ::: body) - } else super.transform(tree).asInstanceOf[Template] - newMembers.clear - tmpl + try deriveTemplate(tree)(transformTrees(newMembers.toList) ::: _) + finally newMembers.clear() + case dd @ DefDef(_, _, _, vparamss0, _, rhs0) => val flatdd = copyDefDef(dd)( vparamss = List(vparamss0.flatten), diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 915d7a98db..2fb9322d54 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -376,7 +376,7 @@ trait MethodSynthesis { override def keepClean = !mods.isParamAccessor override def derivedTree = ( if (mods.isDeferred) EmptyTree - else treeCopy.ValDef(tree, mods | flagsExtra, name, tree.tpt, tree.rhs) + else copyValDef(tree)(mods = mods | flagsExtra, name = this.name) ) } case class Param(tree: ValDef) extends DerivedFromValDef { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 89617e6f2c..5e7fd9ffc4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1548,8 +1548,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R checkOverloadedRestrictions(currentOwner) val bridges = addVarargBridges(currentOwner) checkAllOverrides(currentOwner) - if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges) - else tree + if (bridges.nonEmpty) deriveTemplate(tree)(_ ::: bridges) else tree case dc@TypeTreeWithDeferredRefCheck() => assert(false, "adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc"); dc case tpt@TypeTree() => diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 0ab09b4fec..64f1662a22 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -177,7 +177,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case ModuleDef(_, _, _) => checkCompanionNameClashes(sym) super.transform(tree) - case Template(parents, self, body) => + case Template(_, _, body) => val ownAccDefs = new ListBuffer[Tree] accDefs(currentOwner) = ownAccDefs @@ -189,7 +189,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val body1 = atOwner(currentOwner)(transformTrees(body)) accDefs -= currentOwner ownAccDefs ++= body1 - treeCopy.Template(tree, parents, self, ownAccDefs.toList) + deriveTemplate(tree)(_ => ownAccDefs.toList) case TypeApply(sel @ Select(This(_), name), args) => mayNeedProtectedAccessor(sel, args, false) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index cf90577959..c53b92c5be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -248,11 +248,11 @@ trait SyntheticMethods extends ast.TreeDSL { } if (phase.id > currentRun.typerPhase.id) templ - else treeCopy.Template(templ, templ.parents, templ.self, + else deriveTemplate(templ)(body => if (clazz.isCase) caseTemplateBody() else synthesize() match { - case Nil => templ.body // avoiding unnecessary copy - case ms => templ.body ++ ms + case Nil => body // avoiding unnecessary copy + case ms => body ++ ms } ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1c1f35aac2..25e6de462e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1503,12 +1503,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos) val self1 = templ.self match { - case vd @ ValDef(mods, name, tpt, EmptyTree) => + case vd @ ValDef(_, _, tpt, EmptyTree) => val tpt1 = checkNoEscaping.privates( clazz.thisSym, treeCopy.TypeTree(tpt).setOriginal(tpt) setType vd.symbol.tpe ) - treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType + copyValDef(vd)(tpt = tpt1, rhs = EmptyTree) setType NoType } // was: // val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 9d96f30afb..7d3477a227 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -680,12 +680,41 @@ trait Trees { self: Universe => case t => sys.error("Not a DefDef: " + t + "/" + t.getClass) } + def copyValDef(tree: Tree)( + mods: Modifiers = null, + name: Name = null, + tpt: Tree = null, + rhs: Tree = null + ): ValDef = tree match { + case ValDef(mods0, name0, tpt0, rhs0) => + treeCopy.ValDef(tree, + if (mods eq null) mods0 else mods, + if (name eq null) name0 else name, + if (tpt eq null) tpt0 else tpt, + if (rhs eq null) rhs0 else rhs + ) + case t => + sys.error("Not a ValDef: " + t + "/" + t.getClass) + } + def deriveDefDef(ddef: Tree)(applyToRhs: Tree => Tree): DefDef = ddef match { case DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) => treeCopy.DefDef(ddef, mods0, name0, tparams0, vparamss0, tpt0, applyToRhs(rhs0)) case t => sys.error("Not a DefDef: " + t + "/" + t.getClass) } + def deriveValDef(vdef: Tree)(applyToRhs: Tree => Tree): ValDef = vdef match { + case ValDef(mods0, name0, tpt0, rhs0) => + treeCopy.ValDef(vdef, mods0, name0, tpt0, applyToRhs(rhs0)) + case t => + sys.error("Not a ValDef: " + t + "/" + t.getClass) + } + def deriveTemplate(templ: Tree)(applyToBody: List[Tree] => List[Tree]): Template = templ match { + case Template(parents0, self0, body0) => + treeCopy.Template(templ, parents0, self0, applyToBody(body0)) + case t => + sys.error("Not a Template: " + t + "/" + t.getClass) + } class Traverser { protected var currentOwner: Symbol = definitions.RootClass -- cgit v1.2.3