diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/ast/Trees.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 181 |
1 files changed, 109 insertions, 72 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index f3eaff8db0..855b55bb5e 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -17,7 +17,6 @@ import scala.reflect.internal.Flags.TRAIT trait Trees extends reflect.internal.Trees { self: Global => // --- additional cases -------------------------------------------------------- - /** Only used during parsing */ case class Parens(args: List[Tree]) extends Tree @@ -31,20 +30,22 @@ trait Trees extends reflect.internal.Trees { self: Global => override def isType = definition.isType } - - /** Either an assignment or a named argument. Only appears in argument lists, - * eliminated by typecheck (doTypedApply) - */ - case class AssignOrNamedArg(lhs: Tree, rhs: Tree) - extends TermTree - /** Array selection <qualifier> . <name> only used during erasure */ case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) - extends TermTree with RefTree { } + extends TermTree with RefTree /** emitted by typer, eliminated by refchecks */ case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree + /** Marks underlying reference to id as boxed. + * @pre: id must refer to a captured variable + * A reference such marked will refer to the boxed entity, no dereferencing + * with `.elem` is done on it. + * This tree node can be emitted by macros such as reify that call markBoxedReference. + * It is eliminated in LambdaLift, where the boxing conversion takes place. + */ + case class ReferenceToBoxed(idt: Ident) extends TermTree + // --- factory methods ---------------------------------------------------------- /** Generates a template with constructor corresponding to @@ -77,16 +78,17 @@ trait Trees extends reflect.internal.Trees { self: Global => }}) val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef - val (lvdefs, gvdefs) = evdefs map { + val gvdefs = evdefs map { case vdef @ ValDef(mods, name, tpt, rhs) => - val fld = treeCopy.ValDef( + treeCopy.ValDef( vdef.duplicate, mods, name, atPos(focusPos(vdef.pos)) { TypeTree() setOriginal tpt setPos focusPos(tpt.pos) }, // atPos in case EmptyTree) - val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) - (local, fld) - } unzip - + } + val lvdefs = evdefs map { + case vdef @ ValDef(mods, name, tpt, rhs) => + treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) + } val constrs = { if (constrMods hasFlag TRAIT) { if (body forall treeInfo.isInterfaceMember) List() @@ -147,19 +149,19 @@ trait Trees extends reflect.internal.Trees { self: Global => traverser.traverseTrees(ts) case DocDef(comment, definition) => traverser.traverse(definition) - case AssignOrNamedArg(lhs, rhs) => - traverser.traverse(lhs); traverser.traverse(rhs) case SelectFromArray(qualifier, selector, erasure) => traverser.traverse(qualifier) - case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree? + case ReferenceToBoxed(idt) => + traverser.traverse(idt) + 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.TreeCopierOps { def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray + def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck } @@ -169,10 +171,10 @@ trait Trees extends reflect.internal.Trees { self: Global => class StrictTreeCopier extends super.StrictTreeCopier with TreeCopier { def DocDef(tree: Tree, comment: DocComment, definition: Tree) = new DocDef(comment, definition).copyAttrs(tree) - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = - new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) + def ReferenceToBoxed(tree: Tree, idt: Ident) = + new ReferenceToBoxed(idt).copyAttrs(tree) def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree) } @@ -184,16 +186,16 @@ trait Trees extends reflect.internal.Trees { self: Global => if (comment0 == comment) && (definition0 == definition) => t case _ => this.treeCopy.DocDef(tree, comment, definition) } - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match { - case t @ AssignOrNamedArg(lhs0, rhs0) - if (lhs0 == lhs) && (rhs0 == rhs) => t - case _ => this.treeCopy.AssignOrNamedArg(tree, lhs, rhs) - } 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 ReferenceToBoxed(tree: Tree, idt: Ident) = tree match { + case t @ ReferenceToBoxed(idt0) + if (idt0 == idt) => t + case _ => this.treeCopy.ReferenceToBoxed(tree, idt) + } def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case t @ TypeTreeWithDeferredRefCheck() => t case _ => this.treeCopy.TypeTreeWithDeferredRefCheck(tree) @@ -205,7 +207,7 @@ trait Trees extends reflect.internal.Trees { self: Global => try unit.body = transform(unit.body) catch { case ex: Exception => - println("unhandled exception while transforming "+unit) + println(supplementErrorMessage("unhandled exception while transforming "+unit)) throw ex } } @@ -214,11 +216,12 @@ trait Trees extends reflect.internal.Trees { self: Global => 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 AssignOrNamedArg(lhs, rhs) => - transformer.treeCopy.AssignOrNamedArg(tree, transformer.transform(lhs), transformer.transform(rhs)) case SelectFromArray(qualifier, selector, erasure) => transformer.treeCopy.SelectFromArray( tree, transformer.transform(qualifier), selector, erasure) + case ReferenceToBoxed(idt) => + transformer.treeCopy.ReferenceToBoxed( + tree, transformer.transform(idt) match { case idt1: Ident => idt1 }) case TypeTreeWithDeferredRefCheck() => transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree) } @@ -230,62 +233,97 @@ trait Trees extends reflect.internal.Trees { self: Global => } } - /** resets symbol and tpe fields in a tree, @see ResetAttrsTraverse + /** 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[A<:Tree](x:A): A = new ResetAttrsTransformer(false).transformPoly(x) - def resetLocalAttrs[A<:Tree](x:A): A = new ResetAttrsTransformer(true).transformPoly(x) + + def resetAllAttrs[A<:Tree](x:A): A = new ResetAttrs(false).transform(x) + def resetLocalAttrs[A<:Tree](x:A): A = new ResetAttrs(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) notes where pkg is a pckage: these are kept. + * This(pkg) nodes where pkg is a package: these are kept. * - * (bq:) This traverser has mutable state and should be discarded after use + * (bq:) This transformer has mutable state and should be discarded after use */ - private class ResetAttrsTransformer(localOnly: Boolean) extends Transformer { - private val erasedSyms = util.HashSet[Symbol](8) - private def resetDef(tree: Tree) { - if (tree.symbol != null && tree.symbol != NoSymbol) - erasedSyms addEntry tree.symbol - tree.symbol = NoSymbol + private class ResetAttrs(localOnly: Boolean) { + val debug = settings.debug.value + val trace = scala.tools.nsc.util.trace when debug + + val locals = util.HashSet[Symbol](8) + val orderedLocals = collection.mutable.ListBuffer[Symbol]() + def registerLocal(sym: Symbol) { + if (sym != null && sym != NoSymbol) { + if (debug && !(locals contains sym)) orderedLocals append sym + locals addEntry sym + } } - override def transform(tree: Tree): Tree = super.transform { - tree match { - case Template(_, _, body) => - body foreach resetDef - resetDef(tree) - tree.tpe = null - tree - case _: DefTree | Function(_, _) | Template(_, _, _) => - resetDef(tree) - tree.tpe = null - tree - case tpt: TypeTree => - if (tpt.original != null) - tpt.original - else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => erasedSyms contains tp.typeSymbol)))) - tpt.tpe = null - tree - case TypeApply(fn, args) if args map transform exists (_.isEmpty) => - fn - case This(_) if tree.symbol != null && tree.symbol.isPackageClass => - tree - case EmptyTree => - tree - case _ => - if (tree.hasSymbol && (!localOnly || (erasedSyms contains tree.symbol))) - tree.symbol = NoSymbol - tree.tpe = null - tree + + 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) + } + } + + override def traverse(tree: Tree) = { + tree match { + case _: DefTree | Function(_, _) | Template(_, _, _) => + markLocal(tree) + case _ if tree.symbol.isInstanceOf[FreeVar] => + markLocal(tree) + case _ => + ; + } + + super.traverse(tree) + } + } + + class Transformer extends self.Transformer { + override def transform(tree: Tree): Tree = super.transform { + tree match { + 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.tpe = null + tree + } + case TypeApply(fn, args) if args map transform exists (_.isEmpty) => + transform(fn) + case This(_) if tree.symbol != null && tree.symbol.isPackageClass => + tree + case EmptyTree => + tree + case _ => + if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol))) + tree.symbol = NoSymbol + tree.tpe = null + tree + } } } - def transformPoly[T <: Tree](x: T): T = { - val x1 = transform(x) + + def transform[T <: Tree](x: T): T = { + new MarkLocals().traverse(x) + + if (debug) { + assert(locals.size == orderedLocals.size) + val eoln = System.getProperty("line.separator") + val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString eoln + trace("locals (%d total): %n".format(orderedLocals.size))(msg) + } + + val x1 = new Transformer().transform(x) assert(x.getClass isInstance x1) x1.asInstanceOf[T] } @@ -295,7 +333,6 @@ trait Trees extends reflect.internal.Trees { self: Global => case Parens(expr) (only used during parsing) case DocDef(comment, defn) => (eliminated by typer) - case AssignOrNamedArg(lhs, rhs) => (eliminated by typer) case TypeTreeWithDeferredRefCheck() => (created and eliminated by typer) case SelectFromArray(_, _, _) => (created and eliminated by erasure) |