aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2016-11-04 00:48:36 +0100
committerGitHub <noreply@github.com>2016-11-04 00:48:36 +0100
commit6ba6ea542d7915a48b426fea1f75f9cb8c2db424 (patch)
treef728f6c54fe8c2e57ae136ef08d6fb20eaca534b /src/dotty/tools/dotc/core
parent98a92c6f4ec743edb9465071dcfd43f17dbf054b (diff)
parentd694f15a028cf14ea0cf210d3113c7b1d6af54e7 (diff)
downloaddotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.tar.gz
dotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.tar.bz2
dotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.zip
Merge pull request #1587 from dotty-staging/change-tasty-pos
Fix Tasty positions
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionPickler.scala58
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala11
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala22
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyPickler.scala6
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeBuffer.scala36
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala69
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala99
7 files changed, 195 insertions, 106 deletions
diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
index 63bb00a71..4b67bc188 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
@@ -13,15 +13,32 @@ import collection.mutable
import TastyBuffer._
import util.Positions._
-class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) {
+class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]) {
val buf = new TastyBuffer(5000)
pickler.newSection("Positions", buf)
import buf._
import ast.tpd._
- def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean) = {
+ private val remainingAddrs = new java.util.IdentityHashMap[Tree, Iterator[Addr]]
+
+ def nextTreeAddr(tree: Tree): Option[Addr] = remainingAddrs.get(tree) match {
+ case null =>
+ addrsOfTree(tree) match {
+ case Nil =>
+ None
+ case addr :: Nil =>
+ Some(addr)
+ case addrs =>
+ remainingAddrs.put(tree, addrs.iterator)
+ nextTreeAddr(tree)
+ }
+ case it: Iterator[_] =>
+ if (it.hasNext) Some(it.next) else None
+ }
+
+ def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean) = {
def toInt(b: Boolean) = if (b) 1 else 0
- (addrDelta << 2) | (toInt(hasStartDelta) << 1) | toInt(hasEndDelta)
+ (addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
}
def picklePositions(roots: List[Tree])(implicit ctx: Context) = {
@@ -31,29 +48,46 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr
val addrDelta = index - lastIndex
val startDelta = pos.start - lastPos.start
val endDelta = pos.end - lastPos.end
- buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0))
+ buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0, !pos.isSynthetic))
if (startDelta != 0) buf.writeInt(startDelta)
if (endDelta != 0) buf.writeInt(endDelta)
+ if (!pos.isSynthetic) buf.writeInt(pos.pointDelta)
lastIndex = index
lastPos = pos
}
- def traverse(x: Any, parentPos: Position): Unit = x match {
+
+ /** True if x's position cannot be reconstructed automatically from its initialPos
+ */
+ def alwaysNeedsPos(x: Positioned) = x match {
+ case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field
+ | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
+ case x: Trees.Tree[_] => x.isType // types are unpickled as TypeTrees, so child positions are not available
+ case _ => false
+ }
+
+ def traverse(x: Any): Unit = x match {
case x: Tree @unchecked =>
- if (x.pos.exists && x.pos.toSynthetic != parentPos.toSynthetic) {
- addrOfTree(x) match {
- case Some(addr) => pickleDeltas(addr.index, x.pos)
+ val pos = if (x.isInstanceOf[MemberDef]) x.pos else x.pos.toSynthetic
+ if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) {
+ nextTreeAddr(x) match {
+ case Some(addr) =>
+ //println(i"pickling $x with $pos at $addr")
+ pickleDeltas(addr.index, pos)
case _ =>
+ //println(i"no address for $x")
}
}
+ //else if (x.pos.exists) println(i"skipping $x")
x match {
- case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos)
+ case x: MemberDef @unchecked =>
+ for (ann <- x.symbol.annotations) traverse(ann.tree)
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/PositionUnpickler.scala b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
index c29aeba70..cbe213d89 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
@@ -19,14 +19,17 @@ class PositionUnpickler(reader: TastyReader) {
var curEnd = 0
while (!isAtEnd) {
val header = readInt()
- val addrDelta = header >> 2
- val hasStart = (header & 2) != 0
- val hasEnd = (header & 1) != 0
+ val addrDelta = header >> 3
+ val hasStart = (header & 4) != 0
+ val hasEnd = (header & 2) != 0
+ val hasPoint = (header & 1) != 0
curIndex += addrDelta
assert(curIndex >= 0)
if (hasStart) curStart += readInt()
if (hasEnd) curEnd += readInt()
- positions(Addr(curIndex)) = Position(curStart, curEnd)
+ positions(Addr(curIndex)) =
+ if (hasPoint) Position(curStart, curEnd, curStart + readInt())
+ else Position(curStart, curEnd)
}
positions
}
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index 8e8d58b47..f9743d9d2 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*
@@ -78,6 +79,7 @@ Standard-Section: "ASTs" TopLevelStat*
NAMEDARG Length paramName_NameRef arg_Term
ASSIGN Length lhs_Term rhs_Term
BLOCK Length expr_Term Stat*
+ INLINED Length call_Term expr_Term Stat*
LAMBDA Length meth_Term target_Type
IF Length cond_Term then_Term else_Term
MATCH Length sel_Term CaseDef*
@@ -137,12 +139,11 @@ Standard-Section: "ASTs" TopLevelStat*
BIND Length boundName_NameRef bounds_Type
// for type-variables defined in a type pattern
BYNAMEtype underlying_Type
- LAMBDAtype Length result_Type NamesTypes // variance encoded in front of name: +/-/=
- POLYtype Length result_Type NamesTypes // needed for refinements
+ POLYtype Length result_Type NamesTypes // variance encoded in front of name: +/-/=
METHODtype Length result_Type NamesTypes // needed for refinements
PARAMtype Length binder_ASTref paramNum_Nat // needed for refinements
SHARED type_ASTRef
- NamesTypes = ParamType*
+ NamesTypes = NameType*
NameType = paramName_NameRef typeOrBounds_ASTRef
Modifier = PRIVATE
@@ -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
@@ -305,6 +306,7 @@ object TastyFormat {
final val MATCH = 149
final val RETURN = 150
final val TRY = 151
+ final val INLINED = 152
final val REPEATED = 153
final val BIND = 154
final val ALTERNATIVE = 155
@@ -322,9 +324,8 @@ object TastyFormat {
final val ORtype = 172
final val METHODtype = 174
final val POLYtype = 175
- final val LAMBDAtype = 176
- final val PARAMtype = 177
- final val ANNOTATION = 178
+ final val PARAMtype = 176
+ final val ANNOTATION = 177
final val firstSimpleTreeTag = UNITconst
final val firstNatTreeTag = SHARED
@@ -455,6 +456,7 @@ object TastyFormat {
case LAMBDA => "LAMBDA"
case MATCH => "MATCH"
case RETURN => "RETURN"
+ case INLINED => "INLINED"
case TRY => "TRY"
case REPEATED => "REPEATED"
case BIND => "BIND"
@@ -485,7 +487,7 @@ object TastyFormat {
case PROTECTEDqualified => "PROTECTEDqualified"
}
- /** @return If non-negative, the number of leading references of a length/trees entry.
+ /** @return If non-negative, the number of leading references (represented as nats) of a length/trees entry.
* If negative, minus the number of leading non-reference trees.
*/
def numRefs(tag: Int) = tag match {
diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
index 98b0dc7c6..f847dda68 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
@@ -57,9 +57,11 @@ class TastyPickler {
/**
* Addresses in TASTY file of trees, stored by pickling.
* Note that trees are checked for reference equality,
- * so one can reliably use this function only directly after `pickler`
+ * so one can reliably use this function only directly after `pickler`.
+ * Note that a tree can have several addresses, if it is shared,
+ * i.e. accessible from different paths. Any such sharing is undone by pickling.
*/
- var addrOfTree: tpd.Tree => Option[Addr] = (_ => None)
+ var addrsOfTree: tpd.Tree => List[Addr] = (_ => Nil)
/**
* Addresses in TASTY file of symbols, stored by pickling.
diff --git a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
index d741c42c3..f2681ecde 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) {
@@ -17,11 +17,26 @@ class TreeBuffer extends TastyBuffer(50000) {
private var delta: Array[Int] = _
private var numOffsets = 0
- private[tasty] val pickledTrees = new java.util.IdentityHashMap[Tree, Any] // Value type is really Addr, but that's not compatible with null
+ private type TreeAddrs = Any // really: Addr | List[Addr]
- def addrOfTree(tree: Tree): Option[Addr] = pickledTrees.get(tree) match {
- case null => None
- case n => Some(n.asInstanceOf[Addr])
+ /** A map from trees to the address(es) at which a tree is pickled. There may be several
+ * such addresses if the tree is shared. To keep the map compact, the value type is a
+ * disjunction of a single address (which is the common case) and a list of addresses.
+ */
+ private val treeAddrs = new java.util.IdentityHashMap[Tree, TreeAddrs]
+
+ def registerTreeAddr(tree: Tree) =
+ treeAddrs.put(tree,
+ treeAddrs.get(tree) match {
+ case null => currentAddr
+ case x: Addr => x :: currentAddr :: Nil
+ case xs: List[_] => xs :+ currentAddr
+ })
+
+ def addrsOfTree(tree: Tree): List[Addr] = treeAddrs.get(tree) match {
+ case null => Nil
+ case addr: Addr => addr :: Nil
+ case addrs: List[Addr] => addrs
}
private def offset(i: Int): Addr = Addr(offsets(i))
@@ -147,11 +162,14 @@ class TreeBuffer extends TastyBuffer(50000) {
wasted
}
- def adjustPickledTrees(): Unit = {
- val it = pickledTrees.keySet.iterator
+ def adjustTreeAddrs(): Unit = {
+ val it = treeAddrs.keySet.iterator
while (it.hasNext) {
val tree = it.next
- pickledTrees.put(tree, adjusted(pickledTrees.get(tree).asInstanceOf[Addr]))
+ treeAddrs.get(tree) match {
+ case addr: Addr => treeAddrs.put(tree, adjusted(addr))
+ case addrs: List[Addr] => treeAddrs.put(tree, addrs.map(adjusted))
+ }
}
}
@@ -172,7 +190,7 @@ class TreeBuffer extends TastyBuffer(50000) {
pickling.println(s"adjusting deltas, saved = $saved")
} while (saved > 0 && length / saved < 100)
adjustOffsets()
- adjustPickledTrees()
+ adjustTreeAddrs()
val wasted = compress()
pickling.println(s"original length: $origLength, compressed to: $length, wasted: $wasted") // DEBUG, for now.
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 8889e8a5c..9dfb78798 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
@@ -48,6 +49,10 @@ class TreePickler(pickler: TastyPickler) {
case None =>
}
}
+
+ def rhs(tdef: TypeDef)(implicit ctx: Context) =
+ if (tdef.symbol.isClass) tdef.rhs
+ else TypeTree(tdef.symbol.info).withPos(tdef.rhs.pos)
private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index)
private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index)
@@ -152,6 +157,11 @@ class TreePickler(pickler: TastyPickler) {
throw ex
}
+ def pickleTypeWithPos(tpe: Type, tree: Tree)(implicit ctx: Context): Unit = {
+ registerTreeAddr(tree)
+ pickleType(tpe)
+ }
+
private def pickleNewType(tpe: Type, richTypes: Boolean)(implicit ctx: Context): Unit = try { tpe match {
case AppliedType(tycon, args) =>
writeByte(APPLIEDtype)
@@ -252,7 +262,7 @@ class TreePickler(pickler: TastyPickler) {
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
case tpe: PolyType =>
- writeByte(LAMBDAtype)
+ writeByte(POLYtype)
val paramNames = tpe.typeParams.map(tparam =>
varianceToPrefix(tparam.paramVariance) +: tparam.paramName)
pickleMethodic(tpe.resultType, paramNames, tpe.paramBounds)
@@ -299,7 +309,8 @@ 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 =
+ pickleTypeWithPos(tpt.tpe, tpt) // TODO correlate with original when generating positions
def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit =
if (!tree.isEmpty) pickleTree(tree)
@@ -312,18 +323,21 @@ class TreePickler(pickler: TastyPickler) {
pickleName(sym)
pickleParams
tpt match {
- case tpt: TypeTree => pickleTpt(tpt)
- case _ => pickleTree(tpt)
+ case templ: Template => pickleTree(tpt)
+ case _ if tpt.isType => pickleTpt(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 = {
+ registerTreeAddr(tree)
+ 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, rhs(tree))
+ }
}
def pickleParams(trees: List[Tree])(implicit ctx: Context): Unit = {
@@ -337,8 +351,10 @@ class TreePickler(pickler: TastyPickler) {
}
def pickleTree(tree: Tree)(implicit ctx: Context): Unit = try {
- pickledTrees.put(tree, currentAddr)
+ registerTreeAddr(tree)
tree match {
+ case tree if tree.isType =>
+ pickleTpt(tree)
case Ident(name) =>
tree.tpe match {
case tp: TermRef => pickleType(tp)
@@ -428,17 +444,10 @@ class TreePickler(pickler: TastyPickler) {
case SeqLiteral(elems, elemtpt) =>
writeByte(REPEATED)
withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
- case tree: Inlined =>
- // Why drop Inlined info when pickling?
- // Since we never inline inside an inlined method, we know that
- // any code that continas an Inlined tree is not inlined itself.
- // So position information for inline expansion is no longer needed.
- // The only reason to keep the inline info around would be to have fine-grained
- // position information in the linker. We should come back to this
- // point once we know more what we would do with such information.
- pickleTree(Inliner.dropInlined(tree))
- case TypeTree(original) =>
- pickleTpt(tree)
+ case Inlined(call, bindings, expansion) =>
+ writeByte(INLINED)
+ bindings.foreach(preRegister)
+ withLength { pickleTree(call); pickleTree(expansion); bindings.foreach(pickleTree) }
case Bind(name, body) =>
registerDef(tree.symbol)
writeByte(BIND)
@@ -469,7 +478,7 @@ class TreePickler(pickler: TastyPickler) {
}
pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams)
case tree: TypeDef =>
- pickleDef(TYPEDEF, tree.symbol, tree.rhs)
+ pickleDef(TYPEDEF, tree.symbol, rhs(tree))
case tree: Template =>
registerDef(tree.symbol)
writeByte(TEMPLATE)
@@ -486,6 +495,7 @@ class TreePickler(pickler: TastyPickler) {
if ((selfInfo ne NoType) || !tree.self.isEmpty) {
writeByte(SELFDEF)
pickleName(tree.self.name)
+ if (!tree.self.isEmpty) registerTreeAddr(tree.self.tpt)
pickleType {
cinfo.selfInfo match {
case sym: Symbol => sym.info
@@ -500,12 +510,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 +527,12 @@ class TreePickler(pickler: TastyPickler) {
throw ex
}
+ def pickleSelector(tag: Int, id: untpd.Ident)(implicit ctx: Context): Unit = {
+ registerTreeAddr(id)
+ 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..a0d788955 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -266,7 +266,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType())
registerSym(start, sym)
TypeRef.withFixedSym(NoPrefix, sym.name, sym)
- case LAMBDAtype =>
+ case POLYtype =>
val (rawNames, paramReader) = readNamesSkipParams
val (variances, paramNames) = rawNames
.map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip
@@ -275,13 +275,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
pt => readType())
goto(end)
result
- case POLYtype =>
- val (names, paramReader) = readNamesSkipParams
- val result = PolyType(names.map(_.toTypeName))(
- pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)),
- pt => readType())
- goto(end)
- result
case METHODtype =>
val (names, paramReader) = readNamesSkipParams
val result = MethodType(names.map(_.toTermName), paramReader.readParamTypes[Type](end))(
@@ -383,12 +376,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readTypeRef(): Type =
typeAtAddr(readAddr())
- def readPath()(implicit ctx: Context): Type = {
- val tp = readType()
- assert(tp.isInstanceOf[SingletonType])
- tp
- }
-
def readTermRef()(implicit ctx: Context): TermRef =
readType().asInstanceOf[TermRef]
@@ -655,12 +642,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 +675,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 +693,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 =
@@ -816,21 +811,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] =
@@ -853,7 +855,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readPathTerm(): Tree = {
goto(start)
- readPath() match {
+ readType() match {
case path: TermRef => ref(path)
case path: ThisType => This(path.cls)
case path: ConstantType => Literal(path.value)
@@ -889,6 +891,15 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readLengthTerm(): Tree = {
val end = readEnd()
+ def readBlock(mkTree: (List[Tree], Tree) => Tree): Tree = {
+ val exprReader = fork
+ skipTree()
+ val localCtx = ctx.fresh.setNewScope
+ val stats = readStats(ctx.owner, end)(localCtx)
+ val expr = exprReader.readTerm()(localCtx)
+ mkTree(stats, expr)
+ }
+
val result =
(tag: @switch) match {
case SUPER =>
@@ -921,12 +932,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
case ASSIGN =>
Assign(readTerm(), readTerm())
case BLOCK =>
- val exprReader = fork
- skipTree()
- val localCtx = ctx.fresh.setNewScope
- val stats = readStats(ctx.owner, end)(localCtx)
- val expr = exprReader.readTerm()(localCtx)
- Block(stats, expr)
+ readBlock(Block)
+ case INLINED =>
+ val call = setPos(currentAddr, TypeTree(readType()))
+ readBlock((defs, expr) => Inlined(call, defs.asInstanceOf[List[MemberDef]], expr))
case IF =>
If(readTerm(), readTerm(), readTerm())
case LAMBDA =>
@@ -1002,11 +1011,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} at $addr 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