diff options
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/PositionPickler.scala | 58 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyPickler.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeBuffer.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreePickler.scala | 69 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 99 |
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 |