diff options
author | Martin Odersky <odersky@gmail.com> | 2015-02-23 21:36:13 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2015-03-18 11:14:10 +0100 |
commit | aebc626de6fa762dcd30fd78d0cc2cf3e5a983d4 (patch) | |
tree | ebdc7c25475e706d55d67112552b0bd854e8fc6b /src/dotty/tools | |
parent | 8800adb54f3ac279a2006ed024b40241a6f74219 (diff) | |
download | dotty-aebc626de6fa762dcd30fd78d0cc2cf3e5a983d4.tar.gz dotty-aebc626de6fa762dcd30fd78d0cc2cf3e5a983d4.tar.bz2 dotty-aebc626de6fa762dcd30fd78d0cc2cf3e5a983d4.zip |
First version of unpickler for Positions
Refactored unpickling, splitting into several files.
Diffstat (limited to 'src/dotty/tools')
7 files changed, 715 insertions, 674 deletions
diff --git a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala index ca4f86fe7..e0dc982bd 100644 --- a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala @@ -3,25 +3,9 @@ package dotc package core package pickling -import java.io.IOException - -import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ -import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._ -import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto} -import util.Positions._ -import dotty.tools.dotc.ast.{tpd, Trees, untpd} -import Trees._ -import printing.Texts._ -import printing.Printer -import io.AbstractFile -import util.common._ -import typer.Checking.checkNonCyclic -import Decorators._ +import Contexts._, SymDenotations._ +import dotty.tools.dotc.ast.tpd import TastyUnpickler._, TastyBuffer._ -import annotation.switch -import scala.collection.{ mutable, immutable } -import typer.Mode -import util.Positions object DottyUnpickler { @@ -36,658 +20,30 @@ object DottyUnpickler { * @param moduleroot the top-level module class which is unpickled, or NoSymbol if inapplicable * @param filename filename associated with bytearray, only used for error messages */ -class DottyUnpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation, readPositions: Boolean = false)(ictx: Context) { +class DottyUnpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation, readPositions: Boolean = false)(implicit ctx: Context) { import tpd._ - val moduleRoot = moduleClassRoot.sourceModule(ictx).denot(ictx) + val moduleRoot = moduleClassRoot.sourceModule.denot assert(moduleRoot.isTerm) val unpickler = new TastyUnpickler(bytes) def result: List[Tree] = - unpickler.unpickle(new TreeSectionUnpickler()(ictx)).getOrElse(Nil) - - private val symAtAddr = new mutable.HashMap[Addr, Symbol] - private val defAtAttr = new mutable.HashMap[Addr, MemberDef] - private val typeAtAddr = new mutable.HashMap[Addr, Type] + unpickler.unpickle(new TreeSectionUnpickler()).getOrElse(Nil) + + if (readPositions) + unpickler.unpickle(new PositionsSectionUnpickler()) - class TreeSectionUnpickler(implicit ctx: Context) extends SectionUnpickler[List[Tree]]("ASTs") { + class TreeSectionUnpickler()(implicit ctx: Context) extends SectionUnpickler[List[Tree]]("ASTs") { def unpickle(reader: TastyReader, tastyName: TastyName.Table): List[Tree] = - new TreesUnpickler(reader, tastyName, classRoot.owner, Set(classRoot, moduleClassRoot, moduleRoot), readPositions) + new TreesUnpickler(reader, tastyName, Set(classRoot, moduleClassRoot, moduleRoot), readPositions) .unpickle() } -} - -class TreesUnpickler(reader: TastyReader, tastyName: TastyName.Table, - rootOwner: Symbol, roots: Set[SymDenotation], - readPositions: Boolean) { - import dotty.tools.dotc.core.pickling.PickleFormat._ - import TastyName._ - import tpd._ - - private val symAtAddr = new mutable.HashMap[Addr, Symbol] - private val treeAtAddr = new mutable.HashMap[Addr, Tree] - private val typeAtAddr = new mutable.HashMap[Addr, Type] // currently populated only for types that are known to be SHAREd. - - def unpickle()(implicit ctx: Context): List[Tree] = - new TreeReader(reader).readTopLevelStats() - - def toTermName(tname: TastyName): TermName = tname match { - case Simple(name) => name - case Qualified(qual, name) => toTermName(qual) ++ "." ++ toTermName(name) - case Signed(original, params, result) => toTermName(original) - case Expanded(original) => ??? - case ModuleClass(original) => toTermName(original).moduleClassName.toTermName - case SuperAccessor(accessed) => ??? - case DefaultGetter(meth, num) => ??? - } - - def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) - def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName - - class Completer(reader: TastyReader) extends LazyType { - import reader._ - def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { - treeAtAddr(currentAddr) = new TreeReader(reader).readIndexedDef() - } - } - - class TreeReader(val reader: TastyReader) { - import reader._ - - def forkAt(start: Addr) = new TreeReader(subReader(start, endAddr)) - def fork = forkAt(currentAddr) - - def skipTree(tag: Int): Unit = - if (tag >= firstLengthTreeTag) skipTo(readEnd()) - else if (tag >= firstNatASTTreeTag) { readNat(); skipTree() } - else if (tag >= firstNatTreeTag) readNat() - - def skipTree(): Unit = skipTree(readByte()) - - def skipParams(): Unit = - while (nextByte == PARAM || nextByte== TYPEPARAM) skipTree() - - def readName(): TermName = toTermName(readNameRef()) - - def readNameSplitSig()(implicit ctx: Context): Any /* TermName | (TermName, Signature) */ = - tastyName(readNameRef()) match { - case Signed(original, params, result) => - var sig = Signature(params map toTypeName, toTypeName(result)) - if (sig == Signature.NotAMethod) sig = Signature.NotAMethod - (toTermName(original), sig) - case name => - toTermName(name) - } - -// ------ Reading types ----------------------------------------------------- - - /** Read names in an interleaved sequence of (parameter) names and types/bounds */ - def readParamNames[N <: Name](end: Addr): List[N] = - until(end) { try readName().asInstanceOf[N] finally skipTree() } - - /** Read types or bounds in an interleaved sequence of (parameter) names and types/bounds */ - def readParamTypes[T <: Type](end: Addr)(implicit ctx: Context): List[T] = - until(end) { readNat(); readType().asInstanceOf[T] } - - /** Read referece to definition and return symbol created at that definition */ - def readSymRef()(implicit ctx: Context): Symbol = symAtAddr(readAddr()) - - /** Read a type */ - def readType()(implicit ctx: Context): Type = { - val start = currentAddr - val tag = readByte() - - def registeringType[T](tp: Type, op: => T): T = { - typeAtAddr(start) = tp - op - } - - def readLengthType(): Type = { - val end = readEnd() - - def readNamesSkipParams[N <: Name]: (List[N], TreeReader) = { - val nameReader = fork - nameReader.skipTree() // skip result - val paramReader = nameReader.fork - (nameReader.readParamNames[N](end), paramReader) - } - - try { - (tag: @switch) match { - case THIS => - ThisType.raw(readType().asInstanceOf[TypeRef]) - case SUPERtype => - SuperType(readType(), readType()) - case REFINEDtype => - val parent = readType() - var name: Name = readName() - if (nextByte == TYPEBOUNDS || nextByte == TYPEALIAS) name = name.toTypeName - RefinedType(parent, name, registeringType(_, readType())) - case APPLIEDtype => - readType().appliedTo(until(end)(readType())) - case TYPEBOUNDS => - TypeBounds(readType(), readType()) - case TYPEALIAS => - TypeAlias(readType()) - case ANNOTATED => - AnnotatedType(Annotation(readTerm()), readType()) - case ANDtype => - AndType(readType(), readType()) - case ORtype => - OrType(readType(), readType()) - case BIND => - symAtAddr(start) = - ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType()) - readType() - case BYNAMEtype => - ExprType(readType()) - case POLYtype => - val (names, paramReader) = readNamesSkipParams[TypeName] - try PolyType(names)( - registeringType(_, paramReader.readParamTypes[TypeBounds](end)), - _ => readType()) - finally skipTo(end) - case METHODtype => - val (names, paramReader) = readNamesSkipParams[TermName] - try MethodType(names, paramReader.readParamTypes[Type](end))( - registeringType(_, readType())) - finally skipTo(end) - case PARAMtype => - readTypeRef() match { - case binder: PolyType => PolyParam(binder, readNat()) - case binder: MethodType => MethodParam(binder, readNat()) - } - case CLASSconst => - readEnd() - ConstantType(Constant(readType())) - case ENUMconst => - readEnd() - ConstantType(Constant(readTermRef().termSymbol)) - } - } - finally assert(currentAddr == end) - } - - def readSimpleType(): Type = (tag: @switch) match { - case TYPEREFdirect | TERMREFdirect => - NamedType.withFixedSym(NoPrefix, readSymRef()) - case TYPEREFsymbol | TERMREFsymbol => - val sym = readSymRef() - NamedType.withFixedSym(readType(), sym) - case TYPEREFstatic => - ctx.requiredClass(readName().toTypeName).typeRef - case TERMREFstatic => - ctx.requiredModule(readName()).termRef - case TYPEREF => - val name = readName().toTypeName - TypeRef(readType(), name) - case TERMREF => - readNameSplitSig() match { - case name: TermName => TermRef.all(readType(), name) - case (name: TermName, sig: Signature) => TermRef.withSig(readType(), name, sig) - } - case SKOLEMtype => - SkolemType(readTypeRef()) - case NOTYPE => - NoType - case SHARED => - val ref = readAddr() - typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType()) - case UNITconst => - ConstantType(Constant(())) - case TRUEconst => - ConstantType(Constant(true)) - case FALSEconst => - ConstantType(Constant(false)) - case BYTEconst => - ConstantType(Constant(readInt().toByte)) - case SHORTconst => - ConstantType(Constant(readInt().toShort)) - case CHARconst => - ConstantType(Constant(readNat().toChar)) - case INTconst => - ConstantType(Constant(readInt())) - case LONGconst => - ConstantType(Constant(readLongInt())) - case FLOATconst => - ConstantType(Constant(java.lang.Float.intBitsToFloat(readInt()))) - case DOUBLEconst => - ConstantType(Constant(java.lang.Double.longBitsToDouble(readLongInt()))) - case STRINGconst => - ConstantType(Constant(readName().toString)) - case NULLconst => - ConstantType(Constant(null)) - } - - if (tag < firstLengthTreeTag) readSimpleType() else readLengthType() - } - - 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] - -// ------ Reading definitions ----------------------------------------------------- - - /** Create symbol of definition node and enter in symAtAddr map */ - def createSymbol()(implicit ctx: Context): Unit = { - val start = currentAddr - val tag = readByte() - val end = readEnd() - val name = if (tag == TYPEDEF || tag == TYPEPARAM) readName().toTypeName else readName() - skipParams() - val isAbstractType = nextByte == TYPEBOUNDS - val isClass = nextByte == TEMPLATE - val templateStart = currentAddr - skipTree() - val rhsIsEmpty = - (tag == VALDEF || tag == DEFDEF) && { - val nxTag = readByte() - try nxTag == EMPTYTREE - finally skipTree(nxTag) // skip rhs - } - val (givenFlags, annots, privateWithin) = readModifiers(end) - val lacksDefinition = - rhsIsEmpty && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || - isAbstractType - var flags = givenFlags - if (lacksDefinition) flags |= Deferred - if (ctx.mode.is(Mode.InSuperCall) && !flags.is(ParamOrAccessor)) flags |= InSuperCall - if (ctx.owner.isClass) { - if (tag == TYPEPARAM) flags |= Param - else if (tag == PARAM) flags |= ParamAccessor // TODO: try to unify param and paramaccessor - } - else if (isParamTag(tag)) flags |= Param - val nameMatches = (_: Denotation).symbol.name == name - val isRoot = ctx.owner == rootOwner && roots.exists(nameMatches) - val completer = - if (isRoot) new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter - else new Completer(subReader(start, end)) - def adjustIfModule(completer: Completer) = - if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer - val sym = - if (isRoot) { - val d = roots.find(nameMatches).get - d.info = completer - d.setFlag(flags) - d.privateWithin = privateWithin - d.symbol - } else if (isClass) - ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index) - else { - ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index) - } // TODO set position - sym.annotations = annots - ctx.enter(sym) - symAtAddr(start) = sym - if (isClass) { - completer.withDecls(newScope) - forkAt(templateStart).indexTemplateParams()(ctx.fresh.setOwner(sym)) - } - } - - /** Read modifier list into triplet of flags, annotations and a privateWithin - * boindary symbol. - */ - def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Annotation], Symbol) = { - var flags: FlagSet = EmptyFlags - var annots = new mutable.ListBuffer[Annotation] - var privateWithin: Symbol = NoSymbol - while (currentAddr.index != end.index) { - def addFlag(flag: FlagSet) = { - flags |= flag - readByte() - } - nextByte match { - case PRIVATE => addFlag(Private) - case INTERNAL => ??? // addFlag(Internal) - case PROTECTED => addFlag(Protected) - case ABSTRACT => addFlag(Abstract) - case FINAL => addFlag(Final) - case SEALED => addFlag(Sealed) - case CASE => addFlag(Case) - case IMPLICIT => addFlag(Implicit) - case LAZY => addFlag(Lazy) - case OVERRIDE => addFlag(Override) - case INLINE => addFlag(Inline) - case ABSOVERRIDE => addFlag(AbsOverride) - case STATIC => addFlag(JavaStatic) - case MODULE => addFlag(Module) - case LOCAL => addFlag(Local) - case SYNTHETIC => addFlag(Synthetic) - case ARTIFACT => addFlag(Artifact) - case MUTABLE => addFlag(Mutable) - case LABEL => addFlag(Label) - case FIELDaccessor => addFlag(Accessor) - case PARAMaccessor => addFlag(ParamAccessor) - case CASEaccessor => addFlag(CaseAccessor) - case COVARIANT => addFlag(Covariant) - case CONTRAVARIANT => addFlag(Contravariant) - case SCALA2X => addFlag(Scala2x) - case DEFAULTparameterized => addFlag(DefaultParameterized) - case DEFAULTinit => addFlag(DefaultInit) - case INSUPERCALL => addFlag(InSuperCall) - case PRIVATEqualified => - readByte() - readEnd() - privateWithin = readType().typeSymbol - case PROTECTEDqualified => - addFlag(Protected) - readEnd() - privateWithin = readType().typeSymbol - case ANNOTATION => - readByte() - val end = readEnd() - val sym = readType().typeSymbol - val lazyAnnotTree = readLater(end, _.readTerm()) - annots += Annotation.deferred(sym, _ => lazyAnnotTree.complete) - } - } - (flags, annots.toList, privateWithin) - } - - /** Create symbols for a definitions in statement sequence between - * current address and `end`. - */ - def indexStats(end: Addr)(implicit ctx: Context) = - until(end) { if (isDefTag(nextByte)) createSymbol() else skipTree() } - - /** Create symbols the longest consecutive sequence of parameters with given - * `tag starting at current address. - */ - def indexParams(tag: Int)(implicit ctx: Context) = - while (nextByte == tag) createSymbol() - - /** Create symbols for all type and value parameters of template starting - * at current address. - */ - def indexTemplateParams()(implicit ctx: Context) = { - assert(readByte() == TEMPLATE) - readEnd() - indexParams(TYPEPARAM) - indexParams(PARAM) - } - - /** If definition was already read by a completer, return the previously read tree - * or else read definition. - */ - def readIndexedDef()(implicit ctx: Context): Tree = treeAtAddr.remove(currentAddr) match { - case Some(tree) => skipTree(); tree - case none => readNewDef() - } - - private def readNewDef()(implicit ctx: Context): Tree = { - val start = currentAddr - val sym = symAtAddr(start) - val tag = readByte() - val end = readEnd() - - def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = { - fork.indexParams(tag) - readIndexedParams(tag) - } - - def readParamss(implicit ctx: Context): List[List[ValDef]] = { - collectWhile(nextByte == PARAMS) { - readByte() - readEnd() - readParams[ValDef](PARAM) - } - } - - def readRhs(implicit ctx: Context) = readLater(end, _.readTerm()) - - def localCtx = ctx.fresh.setOwner(sym) - - def ta = ctx.typeAssigner - - readName() - addAddr(start, - tag match { - case DEFDEF => - val tparams = readParams[TypeDef](TYPEPARAM)(localCtx) - val vparamss = readParamss(localCtx) - val tree = ta.assignType( - untpd.DefDef( - sym.name.asTermName, tparams, vparamss, readTpt(), readRhs(localCtx)), - sym) - val typeParams = tparams.map(_.symbol) - val valueParamss = vparamss.nestedMap(_.symbol) - val resType = ctx.effectiveResultType(sym, typeParams, tree.tpt.tpe) - sym.info = ctx.methodType(typeParams, valueParamss, resType) - tree - case VALDEF => - sym.info = readType() - ValDef(sym.asTerm, readRhs(localCtx)) - case TYPEDEF | TYPEPARAM => - if (sym.isClass) - ta.assignType( - untpd.TypeDef(sym.name.asTypeName, readTemplate(localCtx)), - sym) - else { - sym.info = readType() - TypeDef(sym.asType) - } - case PARAM => - sym.info = readType() - ValDef(sym.asTerm) - }) - } - - def readTemplate(implicit ctx: Context): Template = { - val start = currentAddr - val cls = ctx.owner.asClass - val localDummy = ctx.newLocalDummy(cls) - assert(readByte() == TEMPLATE) - val end = readEnd() - readIndexedParams(TYPEPARAM) - readIndexedParams(PARAM) - val parents = collectWhile(nextByte != SELFDEF && nextByte != DEFDEF) { - nextByte match { - case APPLY | TYPEAPPLY => readTerm() - case _ => readTpt() - } - } - fork.indexStats(end) - val self = if (nextByte == SELFDEF) readIndexedDef().asInstanceOf[ValDef] else EmptyValDef - val constr = readIndexedDef().asInstanceOf[DefDef] - val lazyStats = readLater(end, _.readIndexedStats(localDummy, end)) - addAddr(start, - untpd.Template(constr, parents, self, lazyStats) - .withType(localDummy.nonMemberTermRef)) - } - - def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match { - case TYPEDEF | VALDEF | DEFDEF | IMPORT => readIndexedDef() - case _ => readTerm()(ctx.withOwner(exprOwner)) - } - - def readStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = { - fork.indexStats(end) - readIndexedStats(exprOwner, end) - } - - def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = - until(end)(readIndexedStat(exprOwner)) - - def readIndexedParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = - collectWhile(nextByte == tag) { readIndexedDef().asInstanceOf[T] } - -// ------ Reading terms ----------------------------------------------------- - - def readTerm()(implicit ctx: Context): Tree = { - val start = currentAddr - val tag = readByte() - - def readSimpleTerm(): Tree = tag match { - case IDENT => - untpd.Ident(readName()).withType(readType()) - case SELECT => - def readQual(name: Name) = { - val localCtx = - if (name == nme.CONSTRUCTOR) ctx.fresh.addMode(Mode.InSuperCall) else ctx - readTerm()(localCtx) - } - readNameSplitSig match { - case name: Name => readQual(name).select(name) - case (name: Name, sig: Signature) => readQual(name).selectWithSig(name, sig) - } - case EMPTYTREE => - EmptyTree - case _ => - ref(readTermRef()) - } - - def readLengthTerm(): Tree = { - val end = readEnd() - - try { - (tag: @switch) match { - case SUPER => - val qual = readTerm() - val mixClass = ifBefore(end)(readType().typeSymbol, NoSymbol) - val mixName = if (mixClass.exists) mixClass.name.asTypeName else tpnme.EMPTY - tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass) - case APPLY => - val fn = readTerm() - val isJava = fn.tpe.isInstanceOf[JavaMethodType] - def readArg() = readTerm() match { - case SeqLiteral(elems) if isJava => JavaSeqLiteral(elems) - case arg => arg - } - tpd.Apply(readTerm(), until(end)(readArg())) - case TYPEAPPLY => - tpd.TypeApply(readTerm(), until(end)(readTpt())) - case NEW => - New(readTpt()) - case PAIR => - Pair(readTerm(), readTerm()) - case TYPED => - Typed(readTerm(), readTpt()) - case NAMEDARG => - NamedArg(readName(), readTerm()) - case ASSIGN => - Assign(readTerm(), readTerm()) - case BLOCK => - val exprReader = fork - skipTree() - Block(readStats(ctx.owner, end), exprReader.readTerm())(ctx.fresh.setNewScope) - case IF => - If(readTerm(), readTerm(), readTerm()) - case CLOSURE => - val meth = readTerm() - val tpt = readTpt() - Closure(until(end)(readTerm()), meth, tpt) - case MATCH => - Match(readTerm(), readCases()) - case RETURN => - val from = readSymRef() - val expr = ifBefore(end)(readTerm(), EmptyTree) - Return(expr, Ident(from.termRef)) - case TRY => - Try(readTerm(), readCases(), ifBefore(end)(readTerm(), EmptyTree)) - case THROW => - Throw(readTerm()) - case REPEATED => - SeqLiteral(until(end)(readTerm())) - case BIND => - val name = readName() - val info = readType() - val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, info) - symAtAddr(start) = sym - Bind(sym, readTerm()) - case ALTERNATIVE => - Alternative(until(end)(readTerm())) - case UNAPPLY => - val fn = readTerm() - val implicitArgs = - collectWhile(nextByte == IMPLICITARG) { - readByte() - readEnd() - readTerm() - } - val patType = readType() - val argPats = until(end)(readTerm()) - UnApply(fn, implicitArgs, argPats, patType) - } - } - finally assert(currentAddr == end) - } - - addAddr(start, - if (tag < firstLengthTreeTag) readSimpleTerm() - else readLengthTerm()) - } - - def readTpt()(implicit ctx: Context) = { - val start = currentAddr - addAddr(start, TypeTree(readType())) - } - - def readCases()(implicit ctx: Context): List[CaseDef] = - collectWhile(nextByte == CASEDEF) { - val start = currentAddr - readByte() - val end = readEnd() - val pat = readTerm() - val rhs = readTerm() - val guard = ifBefore(end)(readTerm(), EmptyTree) - addAddr(start, CaseDef(pat, guard, rhs)) - } - - def readTopLevelStats()(implicit ctx: Context): List[Tree] = { - fork.indexStats(endAddr) - until(endAddr) { - if (nextByte == PACKAGE) { - val start = currentAddr - readByte() - val end = readEnd() - val pid = ref(readTermRef()).asInstanceOf[RefTree] - addAddr(start, - PackageDef(pid, readStats(NoSymbol, end)(ctx.fresh.setOwner(pid.symbol)))) - } - else readIndexedStat(ctx.owner) - } - } - - def readLater[T](end: Addr, op: TreeReader => T): Trees.Lazy[T] = { - val localReader = fork - skipTo(end) - new Trees.Lazy[T] { def complete: T = op(localReader) } - } - -// ------ Hooks for positions ------------------------------------------------ - -// Temporary position encoding. -// Start field is used for start position once known, address of bytes from which tree is unpickled otherwise -// End field is used for end position once known, address of bytes from which tree is unpickled otherwise -// Point field is coded as follows: -// -// 0 start and end pos known -// 1 start pos unknown, end pos known -// 2 start pos known, end pos unknown -// 3 start pos and end pos unknown - - private final val startUnknown = 1 - private final val endUnknown = 2 - - def indexPosition(addr: Addr): Position = { - assert(addr.index < Positions.MaxOffset) - Position(addr.index, addr.index, startUnknown | endUnknown) - } - - def addAddr[T <: Tree](addr: Addr, tree: T): T = { - if (readPositions) { tree.setPosUnchecked(indexPosition(addr)); tree } - else tree + class PositionsSectionUnpickler()(implicit ctx: Context) extends SectionUnpickler[Unit]("Positions") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { + new OffsetUnpickler(reader, Edge.left).traverse(result) + new OffsetUnpickler(reader, Edge.right).traverse(result) } } } diff --git a/src/dotty/tools/dotc/core/pickling/Edge.scala b/src/dotty/tools/dotc/core/pickling/Edge.scala index dbdc7fe65..59cd85ab2 100644 --- a/src/dotty/tools/dotc/core/pickling/Edge.scala +++ b/src/dotty/tools/dotc/core/pickling/Edge.scala @@ -10,10 +10,11 @@ abstract class Edge { def offset(pos: Position): Int def seq(op1: () => Unit, op2: () => Unit): Unit + def updateOffset(pos: Position, off: Int): Position private val noOp = () => () - def traverseAll(root: Tree)(op: Tree => Unit)(implicit ctx: Context) = { + def traverseAll(roots: List[Tree])(op: Tree => Unit)(implicit ctx: Context) = { def elemsTraversal(xs: TraversableOnce[Any]): () => Unit = (noOp /: xs) ((op, x) => () => seq(op, elemTraversal(x))) @@ -34,7 +35,7 @@ abstract class Edge { () } - elemTraversal(root)() + elemsTraversal(roots)() } } @@ -42,10 +43,12 @@ object Edge { object left extends Edge { def offset(pos: Position): Int = pos.start + def updateOffset(pos: Position, off: Int) = Position(off, pos.end, 0) def seq(op1: () => Unit, op2: () => Unit) = { op1(); op2() } } object right extends Edge { def offset(pos: Position): Int = pos.end + def updateOffset(pos: Position, off: Int) = Position(pos.start, off, 0) def seq(op1: () => Unit, op2: () => Unit) = { op2(); op1() } } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/pickling/OffsetUnpickler.scala b/src/dotty/tools/dotc/core/pickling/OffsetUnpickler.scala new file mode 100644 index 000000000..3fd924114 --- /dev/null +++ b/src/dotty/tools/dotc/core/pickling/OffsetUnpickler.scala @@ -0,0 +1,35 @@ +package dotty.tools +package dotc +package core +package pickling + +import java.io.IOException + +import Contexts._ +import ast.tpd + +/** Unpickler for start or end offset of tree positions */ +class OffsetUnpickler(reader: TastyReader, edge: Edge) { + import reader._ + private val end = readEnd() + private var lastOffset = 0 + private var nextOffset = 0 + private var nextAddr = 0 + + private def next() = { + lastOffset = nextOffset + if (currentAddr != end) { + nextOffset += readInt() + nextAddr += readInt() + } + } + + def traverse(trees: List[tpd.Tree])(implicit ctx: Context) = { + next() + edge.traverseAll(trees) { tree => + if (edge.offset(tree.pos) == nextAddr) next() + tree.setPosUnchecked(edge.updateOffset(tree.pos, lastOffset)) + } + assert(currentAddr == end) + } +}
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/pickling/PositionPickler.scala b/src/dotty/tools/dotc/core/pickling/PositionPickler.scala index 84ab35462..58f00926d 100644 --- a/src/dotty/tools/dotc/core/pickling/PositionPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/PositionPickler.scala @@ -15,15 +15,14 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: Tree => Option[Addr]) { pickler.newSection("Positions", buf) import buf._ - def traverseAll(root: Tree, recorder: PositionRecorder)(implicit ctx: Context) = - recorder.edge.traverseAll(root) { tree => - if (tree.pos.exists) - for (addr <- addrOfTree(tree)) - recorder.record(addr, recorder.edge.offset(tree.pos)) - } - - def picklePositions(root: Tree)(implicit ctx: Context) = { - traverseAll(root, startPos) - traverseAll(root, endPos) + def picklePositions(roots: List[Tree])(implicit ctx: Context) = { + def traverseWith(recorder: PositionRecorder) = + recorder.edge.traverseAll(roots) { tree => + if (tree.pos.exists) + for (addr <- addrOfTree(tree)) + recorder.record(addr, recorder.edge.offset(tree.pos)) + } + traverseWith(startPos) + traverseWith(endPos) } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/pickling/TreePickler.scala b/src/dotty/tools/dotc/core/pickling/TreePickler.scala index 0e6c45d30..60b7a55b0 100644 --- a/src/dotty/tools/dotc/core/pickling/TreePickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreePickler.scala @@ -53,7 +53,7 @@ class TreePickler(pickler: TastyPickler) { forwardSymRefs(sym) = ref :: forwardSymRefs.getOrElse(sym, Nil) } - def pickle(tree: Tree)(implicit ctx: Context) = { + def pickle(trees: List[Tree])(implicit ctx: Context) = { def qualifiedName(sym: Symbol): TastyName = if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName) @@ -467,7 +467,7 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) } } - pickleTree(tree) + trees.foreach(pickleTree) assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %") compactify() } diff --git a/src/dotty/tools/dotc/core/pickling/TreesUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreesUnpickler.scala new file mode 100644 index 000000000..4bc79964a --- /dev/null +++ b/src/dotty/tools/dotc/core/pickling/TreesUnpickler.scala @@ -0,0 +1,648 @@ +package dotty.tools +package dotc +package core +package pickling + +import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ +import StdNames._, Denotations._, Flags._, Constants._, Annotations._ +import util.Positions._ +import dotty.tools.dotc.ast.{tpd, Trees, untpd} +import Trees._ +import Decorators._ +import TastyUnpickler._, TastyBuffer._ +import annotation.switch +import scala.collection.{ mutable, immutable } +import typer.Mode + +/** Unpickler for typed trees + * @param reader the reader from which to unpickle + * @param tastyName the nametable + * @param roots a set of pre-existing symbols whose attributes should be overwritten + * instead of creating a new symbol. + * @param readPositions a flag indicating whether positions should be read + */ +class TreesUnpickler(reader: TastyReader, tastyName: TastyName.Table, + roots: Set[SymDenotation], readPositions: Boolean) { + import dotty.tools.dotc.core.pickling.PickleFormat._ + import TastyName._ + import tpd._ + + private val rootOwner = if (roots.isEmpty) NoSymbol else roots.head.owner + private val symAtAddr = new mutable.HashMap[Addr, Symbol] + private val treeAtAddr = new mutable.HashMap[Addr, Tree] + + private val typeAtAddr = new mutable.HashMap[Addr, Type] // currently populated only for types that are known to be SHAREd. + + def unpickle()(implicit ctx: Context): List[Tree] = + new TreeReader(reader).readTopLevelStats() + + def toTermName(tname: TastyName): TermName = tname match { + case Simple(name) => name + case Qualified(qual, name) => toTermName(qual) ++ "." ++ toTermName(name) + case Signed(original, params, result) => toTermName(original) + case Expanded(original) => ??? + case ModuleClass(original) => toTermName(original).moduleClassName.toTermName + case SuperAccessor(accessed) => ??? + case DefaultGetter(meth, num) => ??? + } + + def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref)) + def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName + + class Completer(reader: TastyReader) extends LazyType { + import reader._ + def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + treeAtAddr(currentAddr) = new TreeReader(reader).readIndexedDef() + } + } + + class TreeReader(val reader: TastyReader) { + import reader._ + + def forkAt(start: Addr) = new TreeReader(subReader(start, endAddr)) + def fork = forkAt(currentAddr) + + def skipTree(tag: Int): Unit = + if (tag >= firstLengthTreeTag) skipTo(readEnd()) + else if (tag >= firstNatASTTreeTag) { readNat(); skipTree() } + else if (tag >= firstNatTreeTag) readNat() + + def skipTree(): Unit = skipTree(readByte()) + + def skipParams(): Unit = + while (nextByte == PARAM || nextByte== TYPEPARAM) skipTree() + + def readName(): TermName = toTermName(readNameRef()) + + def readNameSplitSig()(implicit ctx: Context): Any /* TermName | (TermName, Signature) */ = + tastyName(readNameRef()) match { + case Signed(original, params, result) => + var sig = Signature(params map toTypeName, toTypeName(result)) + if (sig == Signature.NotAMethod) sig = Signature.NotAMethod + (toTermName(original), sig) + case name => + toTermName(name) + } + +// ------ Reading types ----------------------------------------------------- + + /** Read names in an interleaved sequence of (parameter) names and types/bounds */ + def readParamNames[N <: Name](end: Addr): List[N] = + until(end) { try readName().asInstanceOf[N] finally skipTree() } + + /** Read types or bounds in an interleaved sequence of (parameter) names and types/bounds */ + def readParamTypes[T <: Type](end: Addr)(implicit ctx: Context): List[T] = + until(end) { readNat(); readType().asInstanceOf[T] } + + /** Read referece to definition and return symbol created at that definition */ + def readSymRef()(implicit ctx: Context): Symbol = symAtAddr(readAddr()) + + /** Read a type */ + def readType()(implicit ctx: Context): Type = { + val start = currentAddr + val tag = readByte() + + def registeringType[T](tp: Type, op: => T): T = { + typeAtAddr(start) = tp + op + } + + def readLengthType(): Type = { + val end = readEnd() + + def readNamesSkipParams[N <: Name]: (List[N], TreeReader) = { + val nameReader = fork + nameReader.skipTree() // skip result + val paramReader = nameReader.fork + (nameReader.readParamNames[N](end), paramReader) + } + + try { + (tag: @switch) match { + case THIS => + ThisType.raw(readType().asInstanceOf[TypeRef]) + case SUPERtype => + SuperType(readType(), readType()) + case REFINEDtype => + val parent = readType() + var name: Name = readName() + if (nextByte == TYPEBOUNDS || nextByte == TYPEALIAS) name = name.toTypeName + RefinedType(parent, name, registeringType(_, readType())) + case APPLIEDtype => + readType().appliedTo(until(end)(readType())) + case TYPEBOUNDS => + TypeBounds(readType(), readType()) + case TYPEALIAS => + TypeAlias(readType()) + case ANNOTATED => + AnnotatedType(Annotation(readTerm()), readType()) + case ANDtype => + AndType(readType(), readType()) + case ORtype => + OrType(readType(), readType()) + case BIND => + symAtAddr(start) = + ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType()) + readType() + case BYNAMEtype => + ExprType(readType()) + case POLYtype => + val (names, paramReader) = readNamesSkipParams[TypeName] + try PolyType(names)( + registeringType(_, paramReader.readParamTypes[TypeBounds](end)), + _ => readType()) + finally skipTo(end) + case METHODtype => + val (names, paramReader) = readNamesSkipParams[TermName] + try MethodType(names, paramReader.readParamTypes[Type](end))( + registeringType(_, readType())) + finally skipTo(end) + case PARAMtype => + readTypeRef() match { + case binder: PolyType => PolyParam(binder, readNat()) + case binder: MethodType => MethodParam(binder, readNat()) + } + case CLASSconst => + readEnd() + ConstantType(Constant(readType())) + case ENUMconst => + readEnd() + ConstantType(Constant(readTermRef().termSymbol)) + } + } + finally assert(currentAddr == end) + } + + def readSimpleType(): Type = (tag: @switch) match { + case TYPEREFdirect | TERMREFdirect => + NamedType.withFixedSym(NoPrefix, readSymRef()) + case TYPEREFsymbol | TERMREFsymbol => + val sym = readSymRef() + NamedType.withFixedSym(readType(), sym) + case TYPEREFstatic => + ctx.requiredClass(readName().toTypeName).typeRef + case TERMREFstatic => + ctx.requiredModule(readName()).termRef + case TYPEREF => + val name = readName().toTypeName + TypeRef(readType(), name) + case TERMREF => + readNameSplitSig() match { + case name: TermName => TermRef.all(readType(), name) + case (name: TermName, sig: Signature) => TermRef.withSig(readType(), name, sig) + } + case SKOLEMtype => + SkolemType(readTypeRef()) + case NOTYPE => + NoType + case SHARED => + val ref = readAddr() + typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType()) + case UNITconst => + ConstantType(Constant(())) + case TRUEconst => + ConstantType(Constant(true)) + case FALSEconst => + ConstantType(Constant(false)) + case BYTEconst => + ConstantType(Constant(readInt().toByte)) + case SHORTconst => + ConstantType(Constant(readInt().toShort)) + case CHARconst => + ConstantType(Constant(readNat().toChar)) + case INTconst => + ConstantType(Constant(readInt())) + case LONGconst => + ConstantType(Constant(readLongInt())) + case FLOATconst => + ConstantType(Constant(java.lang.Float.intBitsToFloat(readInt()))) + case DOUBLEconst => + ConstantType(Constant(java.lang.Double.longBitsToDouble(readLongInt()))) + case STRINGconst => + ConstantType(Constant(readName().toString)) + case NULLconst => + ConstantType(Constant(null)) + } + + if (tag < firstLengthTreeTag) readSimpleType() else readLengthType() + } + + 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] + +// ------ Reading definitions ----------------------------------------------------- + + /** Create symbol of definition node and enter in symAtAddr map */ + def createSymbol()(implicit ctx: Context): Unit = { + val start = currentAddr + val tag = readByte() + val end = readEnd() + val name = if (tag == TYPEDEF || tag == TYPEPARAM) readName().toTypeName else readName() + skipParams() + val isAbstractType = nextByte == TYPEBOUNDS + val isClass = nextByte == TEMPLATE + val templateStart = currentAddr + skipTree() + val rhsIsEmpty = + (tag == VALDEF || tag == DEFDEF) && { + val nxTag = readByte() + try nxTag == EMPTYTREE + finally skipTree(nxTag) // skip rhs + } + val (givenFlags, annots, privateWithin) = readModifiers(end) + val lacksDefinition = + rhsIsEmpty && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || + isAbstractType + var flags = givenFlags + if (lacksDefinition) flags |= Deferred + if (ctx.mode.is(Mode.InSuperCall) && !flags.is(ParamOrAccessor)) flags |= InSuperCall + if (ctx.owner.isClass) { + if (tag == TYPEPARAM) flags |= Param + else if (tag == PARAM) flags |= ParamAccessor // TODO: try to unify param and paramaccessor + } + else if (isParamTag(tag)) flags |= Param + val nameMatches = (_: Denotation).symbol.name == name + val isRoot = ctx.owner == rootOwner && roots.exists(nameMatches) + val completer = + if (isRoot) new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter + else new Completer(subReader(start, end)) + def adjustIfModule(completer: Completer) = + if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer + val sym = + if (isRoot) { + val d = roots.find(nameMatches).get + d.info = completer + d.setFlag(flags) + d.privateWithin = privateWithin + d.symbol + } else if (isClass) + ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index) + else { + ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index) + } // TODO set position + sym.annotations = annots + ctx.enter(sym) + symAtAddr(start) = sym + if (isClass) { + completer.withDecls(newScope) + forkAt(templateStart).indexTemplateParams()(ctx.fresh.setOwner(sym)) + } + } + + /** Read modifier list into triplet of flags, annotations and a privateWithin + * boindary symbol. + */ + def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Annotation], Symbol) = { + var flags: FlagSet = EmptyFlags + var annots = new mutable.ListBuffer[Annotation] + var privateWithin: Symbol = NoSymbol + while (currentAddr.index != end.index) { + def addFlag(flag: FlagSet) = { + flags |= flag + readByte() + } + nextByte match { + case PRIVATE => addFlag(Private) + case INTERNAL => ??? // addFlag(Internal) + case PROTECTED => addFlag(Protected) + case ABSTRACT => addFlag(Abstract) + case FINAL => addFlag(Final) + case SEALED => addFlag(Sealed) + case CASE => addFlag(Case) + case IMPLICIT => addFlag(Implicit) + case LAZY => addFlag(Lazy) + case OVERRIDE => addFlag(Override) + case INLINE => addFlag(Inline) + case ABSOVERRIDE => addFlag(AbsOverride) + case STATIC => addFlag(JavaStatic) + case MODULE => addFlag(Module) + case LOCAL => addFlag(Local) + case SYNTHETIC => addFlag(Synthetic) + case ARTIFACT => addFlag(Artifact) + case MUTABLE => addFlag(Mutable) + case LABEL => addFlag(Label) + case FIELDaccessor => addFlag(Accessor) + case PARAMaccessor => addFlag(ParamAccessor) + case CASEaccessor => addFlag(CaseAccessor) + case COVARIANT => addFlag(Covariant) + case CONTRAVARIANT => addFlag(Contravariant) + case SCALA2X => addFlag(Scala2x) + case DEFAULTparameterized => addFlag(DefaultParameterized) + case DEFAULTinit => addFlag(DefaultInit) + case INSUPERCALL => addFlag(InSuperCall) + case PRIVATEqualified => + readByte() + readEnd() + privateWithin = readType().typeSymbol + case PROTECTEDqualified => + addFlag(Protected) + readEnd() + privateWithin = readType().typeSymbol + case ANNOTATION => + readByte() + val end = readEnd() + val sym = readType().typeSymbol + val lazyAnnotTree = readLater(end, _.readTerm()) + annots += Annotation.deferred(sym, _ => lazyAnnotTree.complete) + } + } + (flags, annots.toList, privateWithin) + } + + /** Create symbols for a definitions in statement sequence between + * current address and `end`. + */ + def indexStats(end: Addr)(implicit ctx: Context) = + until(end) { if (isDefTag(nextByte)) createSymbol() else skipTree() } + + /** Create symbols the longest consecutive sequence of parameters with given + * `tag starting at current address. + */ + def indexParams(tag: Int)(implicit ctx: Context) = + while (nextByte == tag) createSymbol() + + /** Create symbols for all type and value parameters of template starting + * at current address. + */ + def indexTemplateParams()(implicit ctx: Context) = { + assert(readByte() == TEMPLATE) + readEnd() + indexParams(TYPEPARAM) + indexParams(PARAM) + } + + /** If definition was already read by a completer, return the previously read tree + * or else read definition. + */ + def readIndexedDef()(implicit ctx: Context): Tree = treeAtAddr.remove(currentAddr) match { + case Some(tree) => skipTree(); tree + case none => readNewDef() + } + + private def readNewDef()(implicit ctx: Context): Tree = { + val start = currentAddr + val sym = symAtAddr(start) + val tag = readByte() + val end = readEnd() + + def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = { + fork.indexParams(tag) + readIndexedParams(tag) + } + + def readParamss(implicit ctx: Context): List[List[ValDef]] = { + collectWhile(nextByte == PARAMS) { + readByte() + readEnd() + readParams[ValDef](PARAM) + } + } + + def readRhs(implicit ctx: Context) = readLater(end, _.readTerm()) + + def localCtx = ctx.fresh.setOwner(sym) + + def ta = ctx.typeAssigner + + readName() + addAddr(start, + tag match { + case DEFDEF => + val tparams = readParams[TypeDef](TYPEPARAM)(localCtx) + val vparamss = readParamss(localCtx) + val tree = ta.assignType( + untpd.DefDef( + sym.name.asTermName, tparams, vparamss, readTpt(), readRhs(localCtx)), + sym) + val typeParams = tparams.map(_.symbol) + val valueParamss = vparamss.nestedMap(_.symbol) + val resType = ctx.effectiveResultType(sym, typeParams, tree.tpt.tpe) + sym.info = ctx.methodType(typeParams, valueParamss, resType) + tree + case VALDEF => + sym.info = readType() + ValDef(sym.asTerm, readRhs(localCtx)) + case TYPEDEF | TYPEPARAM => + if (sym.isClass) + ta.assignType( + untpd.TypeDef(sym.name.asTypeName, readTemplate(localCtx)), + sym) + else { + sym.info = readType() + TypeDef(sym.asType) + } + case PARAM => + sym.info = readType() + ValDef(sym.asTerm) + }) + } + + def readTemplate(implicit ctx: Context): Template = { + val start = currentAddr + val cls = ctx.owner.asClass + val localDummy = ctx.newLocalDummy(cls) + assert(readByte() == TEMPLATE) + val end = readEnd() + readIndexedParams(TYPEPARAM) + readIndexedParams(PARAM) + val parents = collectWhile(nextByte != SELFDEF && nextByte != DEFDEF) { + nextByte match { + case APPLY | TYPEAPPLY => readTerm() + case _ => readTpt() + } + } + fork.indexStats(end) + val self = if (nextByte == SELFDEF) readIndexedDef().asInstanceOf[ValDef] else EmptyValDef + val constr = readIndexedDef().asInstanceOf[DefDef] + val lazyStats = readLater(end, _.readIndexedStats(localDummy, end)) + addAddr(start, + untpd.Template(constr, parents, self, lazyStats) + .withType(localDummy.nonMemberTermRef)) + } + + def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match { + case TYPEDEF | VALDEF | DEFDEF | IMPORT => readIndexedDef() + case _ => readTerm()(ctx.withOwner(exprOwner)) + } + + def readStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = { + fork.indexStats(end) + readIndexedStats(exprOwner, end) + } + + def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] = + until(end)(readIndexedStat(exprOwner)) + + def readIndexedParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = + collectWhile(nextByte == tag) { readIndexedDef().asInstanceOf[T] } + +// ------ Reading terms ----------------------------------------------------- + + def readTerm()(implicit ctx: Context): Tree = { + val start = currentAddr + val tag = readByte() + + def readSimpleTerm(): Tree = tag match { + case IDENT => + untpd.Ident(readName()).withType(readType()) + case SELECT => + def readQual(name: Name) = { + val localCtx = + if (name == nme.CONSTRUCTOR) ctx.fresh.addMode(Mode.InSuperCall) else ctx + readTerm()(localCtx) + } + readNameSplitSig match { + case name: Name => readQual(name).select(name) + case (name: Name, sig: Signature) => readQual(name).selectWithSig(name, sig) + } + case EMPTYTREE => + EmptyTree + case _ => + ref(readTermRef()) + } + + def readLengthTerm(): Tree = { + val end = readEnd() + + try { + (tag: @switch) match { + case SUPER => + val qual = readTerm() + val mixClass = ifBefore(end)(readType().typeSymbol, NoSymbol) + val mixName = if (mixClass.exists) mixClass.name.asTypeName else tpnme.EMPTY + tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass) + case APPLY => + val fn = readTerm() + val isJava = fn.tpe.isInstanceOf[JavaMethodType] + def readArg() = readTerm() match { + case SeqLiteral(elems) if isJava => JavaSeqLiteral(elems) + case arg => arg + } + tpd.Apply(readTerm(), until(end)(readArg())) + case TYPEAPPLY => + tpd.TypeApply(readTerm(), until(end)(readTpt())) + case NEW => + New(readTpt()) + case PAIR => + Pair(readTerm(), readTerm()) + case TYPED => + Typed(readTerm(), readTpt()) + case NAMEDARG => + NamedArg(readName(), readTerm()) + case ASSIGN => + Assign(readTerm(), readTerm()) + case BLOCK => + val exprReader = fork + skipTree() + Block(readStats(ctx.owner, end), exprReader.readTerm())(ctx.fresh.setNewScope) + case IF => + If(readTerm(), readTerm(), readTerm()) + case CLOSURE => + val meth = readTerm() + val tpt = readTpt() + Closure(until(end)(readTerm()), meth, tpt) + case MATCH => + Match(readTerm(), readCases()) + case RETURN => + val from = readSymRef() + val expr = ifBefore(end)(readTerm(), EmptyTree) + Return(expr, Ident(from.termRef)) + case TRY => + Try(readTerm(), readCases(), ifBefore(end)(readTerm(), EmptyTree)) + case THROW => + Throw(readTerm()) + case REPEATED => + SeqLiteral(until(end)(readTerm())) + case BIND => + val name = readName() + val info = readType() + val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, info) + symAtAddr(start) = sym + Bind(sym, readTerm()) + case ALTERNATIVE => + Alternative(until(end)(readTerm())) + case UNAPPLY => + val fn = readTerm() + val implicitArgs = + collectWhile(nextByte == IMPLICITARG) { + readByte() + readEnd() + readTerm() + } + val patType = readType() + val argPats = until(end)(readTerm()) + UnApply(fn, implicitArgs, argPats, patType) + } + } + finally assert(currentAddr == end) + } + + addAddr(start, + if (tag < firstLengthTreeTag) readSimpleTerm() + else readLengthTerm()) + } + + def readTpt()(implicit ctx: Context) = { + val start = currentAddr + addAddr(start, TypeTree(readType())) + } + + def readCases()(implicit ctx: Context): List[CaseDef] = + collectWhile(nextByte == CASEDEF) { + val start = currentAddr + readByte() + val end = readEnd() + val pat = readTerm() + val rhs = readTerm() + val guard = ifBefore(end)(readTerm(), EmptyTree) + addAddr(start, CaseDef(pat, guard, rhs)) + } + + def readTopLevelStats()(implicit ctx: Context): List[Tree] = { + fork.indexStats(endAddr) + until(endAddr) { + if (nextByte == PACKAGE) { + val start = currentAddr + readByte() + val end = readEnd() + val pid = ref(readTermRef()).asInstanceOf[RefTree] + addAddr(start, + PackageDef(pid, readStats(NoSymbol, end)(ctx.fresh.setOwner(pid.symbol)))) + } + else readIndexedStat(ctx.owner) + } + } + + def readLater[T](end: Addr, op: TreeReader => T): Trees.Lazy[T] = { + val localReader = fork + skipTo(end) + new Trees.Lazy[T] { def complete: T = op(localReader) } + } + +// ------ Hooks for positions ------------------------------------------------ + + /** A temporary position encoding. + * Start and end fields are each given the address of bytes from which tree is unpickled + * These are later overridden with the actual offsets taken from the Positions section. + */ + def indexPosition(addr: Addr): Position = { + assert(addr.index < MaxOffset) + Position(addr.index, addr.index, 0) + } + + /** Record address from which tree was created as a temporary position in the tree. */ + def addAddr[T <: Tree](addr: Addr, tree: T): T = { + if (readPositions) { tree.setPosUnchecked(indexPosition(addr)); tree } + else tree + } + } +} diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index aa133eeb4..1c604c6e9 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -19,8 +19,8 @@ class Pickler extends MiniPhaseTransform { thisTransform => val pickler = new TastyPickler val treePkl = new TreePickler(pickler) - treePkl.pickle(tree) - new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree) + treePkl.pickle(tree :: Nil) + new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil) val bytes = pickler.assembleParts() def rawBytes = // not needed right now, but useful to print raw format. |