diff options
author | Martin Odersky <odersky@gmail.com> | 2016-10-13 09:39:44 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-10-15 19:33:51 +0200 |
commit | 2575d11bd1a670ace8bd7e91777ea135759af51f (patch) | |
tree | 57d705b50023fecc44247b6ace8ddf9f7865f336 /src | |
parent | 8bfaadaae141e83db7f515b042fcee26ed0e54fd (diff) | |
download | dotty-2575d11bd1a670ace8bd7e91777ea135759af51f.tar.gz dotty-2575d11bd1a670ace8bd7e91777ea135759af51f.tar.bz2 dotty-2575d11bd1a670ace8bd7e91777ea135759af51f.zip |
Preserve all positions in Tasty.
The goal is that pickled and unpickled trees should print
the same with -Yprintpos. There are several reasons why this
is not the case so far. Some of them are fixed in this
commit.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/Positioned.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/PositionPickler.scala | 18 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeBuffer.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreePickler.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 66 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 7 |
8 files changed, 98 insertions, 52 deletions
diff --git a/src/dotty/tools/dotc/ast/Positioned.scala b/src/dotty/tools/dotc/ast/Positioned.scala index 8d364d439..f6793a309 100644 --- a/src/dotty/tools/dotc/ast/Positioned.scala +++ b/src/dotty/tools/dotc/ast/Positioned.scala @@ -107,7 +107,7 @@ abstract class Positioned extends DotClass with Product { /** The initial, synthetic position. This is usually the union of all positioned children's positions. */ - protected def initialPos: Position = { + def initialPos: Position = { var n = productArity var pos = NoPosition while (n > 0) { @@ -139,7 +139,7 @@ abstract class Positioned extends DotClass with Product { (this.pos contains that.pos) && { var n = productArity var found = false - while (n > 0 && !found) { + while (!found && n > 0) { n -= 1 found = isParent(productElement(n)) } diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala index 63bb00a71..65e9d12be 100644 --- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala +++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -37,23 +37,27 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr lastIndex = index lastPos = pos } - def traverse(x: Any, parentPos: Position): Unit = x match { + def traverse(x: Any): Unit = x match { case x: Tree @unchecked => - if (x.pos.exists && x.pos.toSynthetic != parentPos.toSynthetic) { + if (x.pos.exists /*&& x.pos.toSynthetic != x.initialPos.toSynthetic*/) { addrOfTree(x) match { - case Some(addr) => pickleDeltas(addr.index, x.pos) + case Some(addr) => + //println(i"pickling $x") + pickleDeltas(addr.index, x.pos) case _ => + //println(i"no address for $x") } } + //else println(i"skipping $x") x match { - case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos) + case x: MemberDef @unchecked => traverse(x.symbol.annotations) case _ => } - traverse(x.productIterator, x.pos) + traverse(x.productIterator) case xs: TraversableOnce[_] => - xs.foreach(traverse(_, parentPos)) + xs.foreach(traverse) case _ => } - traverse(roots, NoPosition) + traverse(roots) } } diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 8e8d58b47..fc551658b 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -57,7 +57,8 @@ Standard-Section: "ASTs" TopLevelStat* TYPEDEF Length NameRef (Type | Template) Modifier* IMPORT Length qual_Term Selector* Selector = IMPORTED name_NameRef - RENAMED Length from_NameRef to_NameRef + RENAMED to_NameRef + // Imports are for scala.meta, they are not used in the backend TypeParam = TYPEPARAM Length NameRef Type Modifier* @@ -264,6 +265,7 @@ object TastyFormat { final val DOUBLEconst = 76 final val STRINGconst = 77 final val IMPORTED = 78 + final val RENAMED = 79 final val THIS = 96 final val CLASSconst = 97 @@ -291,11 +293,10 @@ object TastyFormat { final val TYPEPARAM = 133 final val PARAMS = 134 final val PARAM = 136 - final val RENAMED = 138 + final val APPLY = 139 final val TYPEAPPLY = 140 - final val TYPED = 143 final val NAMEDARG = 144 final val ASSIGN = 145 diff --git a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala index d741c42c3..f8f7c330f 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala @@ -6,7 +6,7 @@ package tasty import util.Util.{bestFit, dble} import TastyBuffer.{Addr, AddrWidth} import config.Printers.pickling -import ast.tpd.Tree +import ast.untpd.Tree class TreeBuffer extends TastyBuffer(50000) { @@ -19,6 +19,8 @@ class TreeBuffer extends TastyBuffer(50000) { private[tasty] val pickledTrees = new java.util.IdentityHashMap[Tree, Any] // Value type is really Addr, but that's not compatible with null + def registerTreeAddr(tree: Tree) = pickledTrees.put(tree, currentAddr) + def addrOfTree(tree: Tree): Option[Addr] = pickledTrees.get(tree) match { case null => None case n => Some(n.asInstanceOf[Addr]) diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 8889e8a5c..215cef295 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -4,6 +4,7 @@ package core package tasty import ast.Trees._ +import ast.untpd import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable @@ -299,7 +300,10 @@ class TreePickler(pickler: TastyPickler) { pickled } - def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit = pickleType(tpt.tpe) // TODO correlate with original when generating positions + def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit = { + pickledTrees.put(tpt, currentAddr) + pickleType(tpt.tpe) // TODO correlate with original when generating positions + } def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit = if (!tree.isEmpty) pickleTree(tree) @@ -313,17 +317,20 @@ class TreePickler(pickler: TastyPickler) { pickleParams tpt match { case tpt: TypeTree => pickleTpt(tpt) - case _ => pickleTree(tpt) + case templ: Template => pickleTree(tpt) } pickleTreeUnlessEmpty(rhs) pickleModifiers(sym) } } - def pickleParam(tree: Tree)(implicit ctx: Context): Unit = tree match { - case tree: ValDef => pickleDef(PARAM, tree.symbol, tree.tpt) - case tree: DefDef => pickleDef(PARAM, tree.symbol, tree.tpt, tree.rhs) - case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, tree.rhs) + def pickleParam(tree: Tree)(implicit ctx: Context): Unit = { + pickledTrees.put(tree, currentAddr) + tree match { + case tree: ValDef => pickleDef(PARAM, tree.symbol, tree.tpt) + case tree: DefDef => pickleDef(PARAM, tree.symbol, tree.tpt, tree.rhs) + case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, tree.rhs) + } } def pickleParams(trees: List[Tree])(implicit ctx: Context): Unit = { @@ -500,12 +507,11 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleTree(expr) selectors foreach { - case Thicket(Ident(from) :: Ident(to) :: Nil) => - writeByte(RENAMED) - withLength { pickleName(from); pickleName(to) } - case Ident(name) => - writeByte(IMPORTED) - pickleName(name) + case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) => + pickleSelector(IMPORTED, from) + pickleSelector(RENAMED, to) + case id @ Ident(_) => + pickleSelector(IMPORTED, id) } } case PackageDef(pid, stats) => @@ -518,6 +524,12 @@ class TreePickler(pickler: TastyPickler) { throw ex } + def pickleSelector(tag: Int, id: untpd.Ident)(implicit ctx: Context): Unit = { + pickledTrees.put(id, currentAddr) + writeByte(tag) + pickleName(id.name) + } + def qualifiedName(sym: Symbol)(implicit ctx: Context): TastyName = if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName) else TastyName.Qualified(nameIndex(qualifiedName(sym.owner)), nameIndex(sym.name)) diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f67159808..7038f6e0a 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -626,7 +626,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle * or else read definition. */ def readIndexedDef()(implicit ctx: Context): Tree = treeAtAddr.remove(currentAddr) match { - case Some(tree) => skipTree(); tree + case Some(tree) => skipTree(); setPos(currentAddr, tree) case none => readNewDef() } @@ -655,12 +655,18 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle def localCtx = localContext(sym) + def ValDef(tpt: Tree) = + ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(localCtx)), sym) + def DefDef(tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree) = ta.assignType( untpd.DefDef( sym.name.asTermName, tparams, vparamss, tpt, readRhs(localCtx)), sym) + def TypeDef(rhs: Tree) = + ta.assignType(untpd.TypeDef(sym.name.asTypeName, rhs), sym) + def ta = ctx.typeAssigner val name = readName() @@ -682,8 +688,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle } DefDef(tparams, vparamss, tpt) case VALDEF => - sym.info = readType() - ValDef(sym.asTerm, readRhs(localCtx)) + val tpt = readTpt() + sym.info = tpt.tpe + ValDef(tpt) case TYPEDEF | TYPEPARAM => if (sym.isClass) { val companion = sym.scalacLinkedClass @@ -699,22 +706,23 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion) else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion) } - ta.assignType(untpd.TypeDef(sym.name.asTypeName, readTemplate(localCtx)), sym) + TypeDef(readTemplate(localCtx)) } else { - sym.info = readType() - TypeDef(sym.asType) + val rhs = readTpt() + sym.info = rhs.tpe + TypeDef(rhs) } case PARAM => - val info = readType() + val tpt = readTpt() if (noRhs(end)) { - sym.info = info - ValDef(sym.asTerm) + sym.info = tpt.tpe + ValDef(tpt) } else { sym.setFlag(Method) - sym.info = ExprType(info) + sym.info = ExprType(tpt.tpe) pickling.println(i"reading param alias $name -> $currentAddr") - DefDef(Nil, Nil, TypeTree(info)) + DefDef(Nil, Nil, tpt) } } val mods = @@ -752,6 +760,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val parentRefs = ctx.normalizeToClassRefs(parents.map(_.tpe), cls, cls.unforcedDecls) val self = if (nextByte == SELFDEF) { + val selfStart = currentAddr readByte() untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType) } @@ -816,21 +825,28 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle } def readImport()(implicit ctx: Context): Tree = { + val start = currentAddr readByte() readEnd() val expr = readTerm() def readSelectors(): List[untpd.Tree] = nextByte match { - case RENAMED => - readByte() - readEnd() - untpd.Thicket(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors() case IMPORTED => + val start = currentAddr readByte() - untpd.Ident(readName()) :: readSelectors() - case _ => - Nil + val from = setPos(start, untpd.Ident(readName())) + nextByte match { + case RENAMED => + val start2 = currentAddr + readByte() + val to = setPos(start2, untpd.Ident(readName())) + untpd.Thicket(from, to) :: readSelectors() + case _ => + from :: readSelectors() + } + case _ => + Nil } - Import(expr, readSelectors()) + setPos(start, Import(expr, readSelectors())) } def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = @@ -1002,11 +1018,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle // ------ Setting positions ------------------------------------------------ /** Set position of `tree` at given `addr`. */ - def setPos[T <: Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type = + def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type = if (ctx.mode.is(Mode.ReadPositions)) { posUnpicklerOpt match { - case Some(posUnpickler) => tree.withPos(posUnpickler.posAt(addr)) - case _ => tree + case Some(posUnpickler) => + //println(i"setPos $tree / ${tree.getClass} to ${posUnpickler.posAt(addr)}") + val pos = posUnpickler.posAt(addr) + if (pos.exists) tree.setPosUnchecked(pos) + tree + case _ => + //println(i"no pos $tree") + tree } } else tree diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 6315cfabc..7f88e246b 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -426,7 +426,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case _ => toTextGlobal(sel) } val selectorsText: Text = selectors match { - case Ident(name) :: Nil => toText(name) + case id :: Nil => toText(id) case _ => "{" ~ Text(selectors map selectorText, ", ") ~ "}" } "import " ~ toTextLocal(expr) ~ "." ~ selectorsText @@ -525,8 +525,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.isType) txt = toText(tp) else if (!tree.isDef) txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close } - if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]]) - txt = txt ~ "@" ~ tree.pos.toString + if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]]) { + val pos = if (homogenizedView) tree.pos.toSynthetic else tree.pos + txt = txt ~ "@" ~ pos.toString + } tree match { case Block(_, _) | Template(_, _, _, _) => txt case _ => txt.close diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index 90e62b65c..2fb85b6c0 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -66,7 +66,10 @@ class Pickler extends Phase { override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { val result = super.runOn(units) if (ctx.settings.YtestPickler.value) - testUnpickler(units)(ctx.fresh.setPeriod(Period(ctx.runId + 1, FirstPhaseId))) + testUnpickler(units)( + ctx.fresh + .setPeriod(Period(ctx.runId + 1, FirstPhaseId)) + .addMode(Mode.ReadPositions)) result } @@ -81,7 +84,7 @@ class Pickler extends Phase { } pickling.println("************* entered toplevel ***********") for ((cls, unpickler) <- unpicklers) { - val unpickled = unpickler.body(ctx.addMode(Mode.ReadPositions)) + val unpickled = unpickler.body testSame(i"$unpickled%\n%", beforePickling(cls), cls) } } |