diff options
author | Dmitry Petrashko <dark@d-d.me> | 2016-01-04 11:41:39 +0100 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2016-01-04 11:41:39 +0100 |
commit | 013c82356d2bf000edaed164ae8f369e43d0072c (patch) | |
tree | 7172aa58ec832838bcecce915e73b86fd9287222 /src | |
parent | 4bca33233bb11e9a8ef8461b66707c37e8a09184 (diff) | |
parent | ef73669cef8f34257176c4720c0b5c0e63d98c3e (diff) | |
download | dotty-013c82356d2bf000edaed164ae8f369e43d0072c.tar.gz dotty-013c82356d2bf000edaed164ae8f369e43d0072c.tar.bz2 dotty-013c82356d2bf000edaed164ae8f369e43d0072c.zip |
Merge pull request #1003 from dotty-staging/linker/tasty
Fixes&Changes to TASTY inspired by Linker
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/CompilationUnit.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/FromTasty.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala | 33 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyPickler.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyReader.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreePickler.scala | 550 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 28 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 2 |
10 files changed, 339 insertions, 296 deletions
diff --git a/src/dotty/tools/dotc/CompilationUnit.scala b/src/dotty/tools/dotc/CompilationUnit.scala index 6f05b831f..16a59250b 100644 --- a/src/dotty/tools/dotc/CompilationUnit.scala +++ b/src/dotty/tools/dotc/CompilationUnit.scala @@ -2,7 +2,7 @@ package dotty.tools package dotc import dotty.tools.dotc.core.Types.Type -import dotty.tools.dotc.core.tasty.{TastyBuffer, TastyPickler} +import dotty.tools.dotc.core.tasty.{TastyUnpickler, TastyBuffer, TastyPickler} import util.SourceFile import ast.{tpd, untpd} import dotty.tools.dotc.core.Symbols._ @@ -23,4 +23,6 @@ class CompilationUnit(val source: SourceFile) { * Subsequent phases can add new sections. */ var picklers: Map[ClassSymbol, TastyPickler] = Map() + + var unpicklers: Map[ClassSymbol, TastyUnpickler] = Map() } diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala index 705deedd3..d8d8b8b1e 100644 --- a/src/dotty/tools/dotc/FromTasty.scala +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -86,6 +86,7 @@ object FromTasty extends Driver { val (List(unpickled), source) = unpickler.body(readPositions = true) val unit1 = new CompilationUnit(source) unit1.tpdTree = unpickled + unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler) force.traverse(unit1.tpdTree) unit1 case _ => diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index e351557a3..8016c57f3 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -69,7 +69,7 @@ object SymDenotations { ownerIfExists: Symbol, final val name: Name, initFlags: FlagSet, - initInfo: Type, + final val initInfo: Type, initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) { //assert(symbol.id != 4940, name) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index b72185492..1086fcdd6 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1011,6 +1011,14 @@ object Types { case _ => Nil } + /** The parameter names of a PolyType or MethodType, Empty list for others */ + final def paramNamess(implicit ctx: Context): List[List[TermName]] = this match { + case mt: MethodType => mt.paramNames :: mt.resultType.paramNamess + case pt: PolyType => pt.resultType.paramNamess + case _ => Nil + } + + /** The parameter types in the first parameter section of a PolyType or MethodType, Empty list for others */ final def firstParamTypes(implicit ctx: Context): List[Type] = this match { case mt: MethodType => mt.paramTypes diff --git a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index ccd3f78e8..d62762571 100644 --- a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -6,6 +6,7 @@ package tasty import Contexts._, SymDenotations._ import dotty.tools.dotc.ast.tpd import TastyUnpickler._, TastyBuffer._ +import dotty.tools.dotc.core.tasty.DottyUnpickler.{SourceFileUnpickler, TreeSectionUnpickler, PositionsSectionUnpickler} import util.Positions._ import util.{SourceFile, NoSource} import PositionUnpickler._ @@ -15,6 +16,21 @@ object DottyUnpickler { /** Exception thrown if classfile is corrupted */ class BadSignature(msg: String) extends RuntimeException(msg) + + class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + new SourceFile(tastyName(reader.readNameRef()).toString, Seq()) + } + + class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + new TreeUnpickler(reader, tastyName) + } + + class PositionsSectionUnpickler extends SectionUnpickler[(Position, AddrToPosition)]("Positions") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + new PositionUnpickler(reader).unpickle() + } } /** A class for unpickling Tasty trees and symbols. @@ -23,7 +39,7 @@ object DottyUnpickler { class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded { import tpd._ - private val unpickler = new TastyUnpickler(bytes) + val unpickler = new TastyUnpickler(bytes) private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler).get /** Enter all toplevel classes and objects into their scopes @@ -42,19 +58,4 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded { treeUnpickler.usePositions(totalRange, positions) (treeUnpickler.unpickle(), source) } - - private class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = - new SourceFile(tastyName(reader.readNameRef()).toString, Seq()) - } - - private class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = - new TreeUnpickler(reader, tastyName) - } - - private class PositionsSectionUnpickler extends SectionUnpickler[(Position, AddrToPosition)]("Positions") { - def unpickle(reader: TastyReader, tastyName: TastyName.Table) = - new PositionUnpickler(reader).unpickle() - } } diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala index f53a97c0c..83e6020d5 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala @@ -13,13 +13,13 @@ import ast.tpd class TastyPickler { private val sections = new mutable.ArrayBuffer[(TastyName.NameRef, TastyBuffer)] + val uuid = UUID.randomUUID() private val headerBuffer = { val buf = new TastyBuffer(24) for (ch <- header) buf.writeByte(ch.toByte) buf.writeNat(MajorVersion) buf.writeNat(MinorVersion) - val uuid = UUID.randomUUID() buf.writeUncompressedLong(uuid.getMostSignificantBits) buf.writeUncompressedLong(uuid.getLeastSignificantBits) buf @@ -31,6 +31,7 @@ class TastyPickler { sections += ((nameBuffer.nameIndex(name), buf)) def assembleParts(): Array[Byte] = { + treePkl.compactify() def lengthWithLength(buf: TastyBuffer) = { buf.assemble() buf.length + natSize(buf.length) @@ -67,4 +68,6 @@ class TastyPickler { * so one can reliably use this function only dirrectly after `pickler` */ var addrOfSym: Symbol => Option[Addr] = (_ => None) + + val treePkl = new TreePickler(this) } diff --git a/src/dotty/tools/dotc/core/tasty/TastyReader.scala b/src/dotty/tools/dotc/core/tasty/TastyReader.scala index c6a222d2b..e583c4793 100644 --- a/src/dotty/tools/dotc/core/tasty/TastyReader.scala +++ b/src/dotty/tools/dotc/core/tasty/TastyReader.scala @@ -99,7 +99,7 @@ class TastyReader(val bytes: Array[Byte], start: Int, end: Int, val base: Int = /** Read an uncompressed Long stored in 8 bytes in big endian format */ def readUncompressedLong(): Long = { - var x = 0 + var x: Long = 0 for (i <- 0 to 7) x = (x << 8) | (readByte() & 0xff) x diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d11d6f4b7..bb6c3cd2e 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -80,225 +80,251 @@ class TreePickler(pickler: TastyPickler) { case None => false } - def pickle(trees: List[Tree])(implicit ctx: Context) = { + def pickleConstant(c: Constant)(implicit ctx: Context): Unit = c.tag match { + case UnitTag => + writeByte(UNITconst) + case BooleanTag => + writeByte(if (c.booleanValue) TRUEconst else FALSEconst) + case ByteTag => + writeByte(BYTEconst) + writeInt(c.byteValue) + case ShortTag => + writeByte(SHORTconst) + writeInt(c.shortValue) + case CharTag => + writeByte(CHARconst) + writeNat(c.charValue) + case IntTag => + writeByte(INTconst) + writeInt(c.intValue) + case LongTag => + writeByte(LONGconst) + writeLongInt(c.longValue) + case FloatTag => + writeByte(FLOATconst) + writeInt(java.lang.Float.floatToRawIntBits(c.floatValue)) + case DoubleTag => + writeByte(DOUBLEconst) + writeLongInt(java.lang.Double.doubleToRawLongBits(c.doubleValue)) + case StringTag => + writeByte(STRINGconst) + writeNat(nameIndex(c.stringValue).index) + case NullTag => + writeByte(NULLconst) + case ClazzTag => + writeByte(CLASSconst) + pickleType(c.typeValue) + case EnumTag => + writeByte(ENUMconst) + pickleType(c.symbolValue.termRef) + } - def qualifiedName(sym: Symbol): TastyName = - if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName) - else TastyName.Qualified(nameIndex(qualifiedName(sym.owner)), nameIndex(sym.name)) - - def pickleConstant(c: Constant): Unit = c.tag match { - case UnitTag => - writeByte(UNITconst) - case BooleanTag => - writeByte(if (c.booleanValue) TRUEconst else FALSEconst) - case ByteTag => - writeByte(BYTEconst) - writeInt(c.byteValue) - case ShortTag => - writeByte(SHORTconst) - writeInt(c.shortValue) - case CharTag => - writeByte(CHARconst) - writeNat(c.charValue) - case IntTag => - writeByte(INTconst) - writeInt(c.intValue) - case LongTag => - writeByte(LONGconst) - writeLongInt(c.longValue) - case FloatTag => - writeByte(FLOATconst) - writeInt(java.lang.Float.floatToRawIntBits(c.floatValue)) - case DoubleTag => - writeByte(DOUBLEconst) - writeLongInt(java.lang.Double.doubleToRawLongBits(c.doubleValue)) - case StringTag => - writeByte(STRINGconst) - writeNat(nameIndex(c.stringValue).index) - case NullTag => - writeByte(NULLconst) - case ClazzTag => - writeByte(CLASSconst) - pickleType(c.typeValue) - case EnumTag => - writeByte(ENUMconst) - pickleType(c.symbolValue.termRef) + def pickleType(tpe0: Type, richTypes: Boolean = false)(implicit ctx: Context): Unit = try { + val tpe = tpe0.stripTypeVar + val prev = pickledTypes.get(tpe) + if (prev == null) { + pickledTypes.put(tpe, currentAddr) + pickleNewType(tpe, richTypes) } - - def pickleType(tpe0: Type, richTypes: Boolean = false): Unit = try { - val tpe = tpe0.stripTypeVar - val prev = pickledTypes.get(tpe) - if (prev == null) { - pickledTypes.put(tpe, currentAddr) - pickleNewType(tpe, richTypes) - } - else { - writeByte(SHARED) - writeRef(prev.asInstanceOf[Addr]) - } - } catch { - case ex: AssertionError => - println(i"error when pickling type $tpe0") - throw ex + else { + writeByte(SHARED) + writeRef(prev.asInstanceOf[Addr]) } + } catch { + case ex: AssertionError => + println(i"error when pickling type $tpe0") + throw ex + } - def pickleNewType(tpe: Type, richTypes: Boolean): Unit = try { tpe match { - case AppliedType(tycon, args) => - writeByte(APPLIEDtype) - withLength { pickleType(tycon); args.foreach(pickleType(_)) } - case ConstantType(value) => - pickleConstant(value) - case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.is(Flags.AliasPreferred) => - pickleType(tpe.info.bounds.hi) - case tpe: WithFixedSym => - val sym = tpe.symbol - def pickleRef() = - if (tpe.prefix == NoPrefix) { - writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) - pickleSymRef(sym) - } - else { - assert(tpe.symbol.isClass) - assert(tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated) - writeByte(TYPEREF) // should be changed to a new entry that keeps track of prefix, symbol & owner - pickleName(tpe.name) - pickleType(tpe.prefix) - } - if (sym.is(Flags.Package)) { - writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) - pickleName(qualifiedName(sym)) + private def pickleNewType(tpe: Type, richTypes: Boolean)(implicit ctx: Context): Unit = try { tpe match { + case AppliedType(tycon, args) => + writeByte(APPLIEDtype) + withLength { pickleType(tycon); args.foreach(pickleType(_)) } + case ConstantType(value) => + pickleConstant(value) + case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.is(Flags.AliasPreferred) => + pickleType(tpe.info.bounds.hi) + case tpe: WithFixedSym => + val sym = tpe.symbol + def pickleRef() = + if (tpe.prefix == NoPrefix) { + writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) + pickleSymRef(sym) } - else if (sym is Flags.BindDefinedType) { - registerDef(sym) - writeByte(BIND) - withLength { - pickleName(sym.name) - pickleType(sym.info) - pickleRef() - } - } - else pickleRef() - case tpe: TermRefWithSignature => - if (tpe.symbol.is(Flags.Package)) picklePackageRef(tpe.symbol) - else { - writeByte(TERMREF) - pickleNameAndSig(tpe.name, tpe.signature); pickleType(tpe.prefix) - } - case tpe: NamedType => - if (isLocallyDefined(tpe.symbol)) { - writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) - pickleSymRef(tpe.symbol); pickleType(tpe.prefix) - } else { - writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(tpe.name); pickleType(tpe.prefix) - } - case tpe: ThisType => - if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) - picklePackageRef(tpe.cls) else { - writeByte(THIS) - pickleType(tpe.tref) + assert(tpe.symbol.isClass) + assert(tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated) + writeByte(TYPEREF) // should be changed to a new entry that keeps track of prefix, symbol & owner + pickleName(tpe.name) + pickleType(tpe.prefix) } - case tpe: SuperType => - writeByte(SUPERtype) - withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe)} - case tpe: RefinedThis => - writeByte(REFINEDthis) - val binderAddr = pickledTypes.get(tpe.binder) - assert(binderAddr != null, tpe.binder) - writeRef(binderAddr.asInstanceOf[Addr]) - case tpe: SkolemType => - pickleType(tpe.info) - case tpe: RefinedType => - writeByte(REFINEDtype) + if (sym.is(Flags.Package)) { + writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) + pickleName(qualifiedName(sym)) + } + else if (sym is Flags.BindDefinedType) { + registerDef(sym) + writeByte(BIND) withLength { - pickleType(tpe.parent) - pickleName(tpe.refinedName) - pickleType(tpe.refinedInfo, richTypes = true) + pickleName(sym.name) + pickleType(sym.info) + pickleRef() } - case tpe: TypeAlias => - writeByte(TYPEALIAS) - withLength { - pickleType(tpe.alias, richTypes) - tpe.variance match { - case 1 => writeByte(COVARIANT) - case -1 => writeByte(CONTRAVARIANT) - case 0 => - } + } + else pickleRef() + case tpe: TermRefWithSignature => + if (tpe.symbol.is(Flags.Package)) picklePackageRef(tpe.symbol) + else { + writeByte(TERMREF) + pickleNameAndSig(tpe.name, tpe.signature); pickleType(tpe.prefix) + } + case tpe: NamedType => + if (isLocallyDefined(tpe.symbol)) { + writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) + pickleSymRef(tpe.symbol); pickleType(tpe.prefix) + } else { + writeByte(if (tpe.isType) TYPEREF else TERMREF) + pickleName(tpe.name); pickleType(tpe.prefix) + } + case tpe: ThisType => + if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) + picklePackageRef(tpe.cls) + else { + writeByte(THIS) + pickleType(tpe.tref) + } + case tpe: SuperType => + writeByte(SUPERtype) + withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe)} + case tpe: RefinedThis => + writeByte(REFINEDthis) + val binderAddr = pickledTypes.get(tpe.binder) + assert(binderAddr != null, tpe.binder) + writeRef(binderAddr.asInstanceOf[Addr]) + case tpe: SkolemType => + pickleType(tpe.info) + case tpe: RefinedType => + writeByte(REFINEDtype) + withLength { + pickleType(tpe.parent) + pickleName(tpe.refinedName) + pickleType(tpe.refinedInfo, richTypes = true) + } + case tpe: TypeAlias => + writeByte(TYPEALIAS) + withLength { + pickleType(tpe.alias, richTypes) + tpe.variance match { + case 1 => writeByte(COVARIANT) + case -1 => writeByte(CONTRAVARIANT) + case 0 => } - case tpe: TypeBounds => - writeByte(TYPEBOUNDS) - withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) } - case tpe: AnnotatedType => - writeByte(ANNOTATED) - withLength { pickleType(tpe.tpe, richTypes); pickleTree(tpe.annot.tree) } - case tpe: AndOrType => - writeByte(if (tpe.isAnd) ANDtype else ORtype) - withLength { pickleType(tpe.tp1, richTypes); pickleType(tpe.tp2, richTypes) } - case tpe: ExprType => - writeByte(BYNAMEtype) - pickleType(tpe.underlying) - case tpe: MethodType if richTypes => - writeByte(METHODtype) - pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes) - case tpe: PolyType if richTypes => - writeByte(POLYtype) - pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramBounds) - case tpe: PolyParam => - if (!pickleParamType(tpe)) - // TODO figure out why this case arises in e.g. pickling AbstractFileReader. - ctx.typerState.constraint.entry(tpe) match { - case TypeBounds(lo, hi) if lo eq hi => pickleNewType(lo, richTypes) - case _ => assert(false, s"orphan poly parameter: $tpe") - } - case tpe: MethodParam => - assert(pickleParamType(tpe), s"orphan method parameter: $tpe") - case tpe: LazyRef => - pickleType(tpe.ref) - }} catch { - case ex: AssertionError => - println(i"error while pickling type $tpe") - throw ex + } + case tpe: TypeBounds => + writeByte(TYPEBOUNDS) + withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) } + case tpe: AnnotatedType => + writeByte(ANNOTATED) + withLength { pickleType(tpe.tpe, richTypes); pickleTree(tpe.annot.tree) } + case tpe: AndOrType => + writeByte(if (tpe.isAnd) ANDtype else ORtype) + withLength { pickleType(tpe.tp1, richTypes); pickleType(tpe.tp2, richTypes) } + case tpe: ExprType => + writeByte(BYNAMEtype) + pickleType(tpe.underlying) + case tpe: MethodType if richTypes => + writeByte(METHODtype) + pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes) + case tpe: PolyType if richTypes => + writeByte(POLYtype) + pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramBounds) + case tpe: PolyParam => + if (!pickleParamType(tpe)) + // TODO figure out why this case arises in e.g. pickling AbstractFileReader. + ctx.typerState.constraint.entry(tpe) match { + case TypeBounds(lo, hi) if lo eq hi => pickleNewType(lo, richTypes) + case _ => assert(false, s"orphan poly parameter: $tpe") + } + case tpe: MethodParam => + assert(pickleParamType(tpe), s"orphan method parameter: $tpe") + case tpe: LazyRef => + pickleType(tpe.ref) + }} catch { + case ex: AssertionError => + println(i"error while pickling type $tpe") + throw ex + } + + def picklePackageRef(pkg: Symbol)(implicit ctx: Context): Unit = { + writeByte(TERMREFpkg) + pickleName(qualifiedName(pkg)) + } + + def pickleMethodic(result: Type, names: List[Name], types: List[Type])(implicit ctx: Context) = + withLength { + pickleType(result, richTypes = true) + (names, types).zipped.foreach { (name, tpe) => + pickleName(name); pickleType(tpe) + } } - def picklePackageRef(pkg: Symbol): Unit = { - writeByte(TERMREFpkg) - pickleName(qualifiedName(pkg)) + def pickleParamType(tpe: ParamType)(implicit ctx: Context): Boolean = { + val binder = pickledTypes.get(tpe.binder) + val pickled = binder != null + if (pickled) { + writeByte(PARAMtype) + withLength { writeRef(binder.asInstanceOf[Addr]); writeNat(tpe.paramNum) } } + pickled + } - def pickleMethodic(result: Type, names: List[Name], types: List[Type]) = - withLength { - pickleType(result, richTypes = true) - (names, types).zipped.foreach { (name, tpe) => - pickleName(name); pickleType(tpe) - } - } + def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit = pickleType(tpt.tpe) // TODO correlate with original when generating positions + + def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit = + if (!tree.isEmpty) pickleTree(tree) - def pickleParamType(tpe: ParamType): Boolean = { - val binder = pickledTypes.get(tpe.binder) - val pickled = binder != null - if (pickled) { - writeByte(PARAMtype) - withLength { writeRef(binder.asInstanceOf[Addr]); writeNat(tpe.paramNum) } + def pickleDef(tag: Int, sym: Symbol, tpt: Tree, rhs: Tree = EmptyTree, pickleParams: => Unit = ())(implicit ctx: Context) = { + assert(symRefs(sym) == NoAddr) + registerDef(sym) + writeByte(tag) + withLength { + pickleName(sym) + pickleParams + tpt match { + case tpt: TypeTree => pickleTpt(tpt) + case _ => pickleTree(tpt) } - pickled + pickleTreeUnlessEmpty(rhs) + pickleModifiers(sym) } + } - def pickleTpt(tpt: Tree): Unit = pickleType(tpt.tpe) // TODO correlate with original when generating positions + 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 pickleTreeUnlessEmpty(tree: Tree): Unit = - if (!tree.isEmpty) pickleTree(tree) + def pickleParams(trees: List[Tree])(implicit ctx: Context): Unit = { + trees.foreach(preRegister) + trees.foreach(pickleParam) + } + + def pickleStats(stats: List[Tree])(implicit ctx: Context) = { + stats.foreach(preRegister) + stats.foreach(stat => if (!stat.isEmpty) pickleTree(stat)) + } - def pickleTree(tree: Tree): Unit = try { - pickledTrees.put(tree, currentAddr) - tree match { + def pickleTree(tree: Tree)(implicit ctx: Context): Unit = try { + pickledTrees.put(tree, currentAddr) + tree match { case Ident(name) => tree.tpe match { case tp: TermRef => pickleType(tp) case _ => - writeByte(IDENT) - pickleName(name) - pickleType(tree.tpe) + writeByte(IDENT) + pickleName(name) + pickleType(tree.tpe) } case This(_) => pickleType(tree.tpe) @@ -459,95 +485,73 @@ class TreePickler(pickler: TastyPickler) { writeByte(PACKAGE) withLength { pickleType(pid.tpe); pickleStats(stats) } }} - catch { - case ex: AssertionError => - println(i"error when pickling tree $tree") - throw ex - } + catch { + case ex: AssertionError => + println(i"error when pickling tree $tree") + throw ex + } - def pickleDef(tag: Int, sym: Symbol, tpt: Tree, rhs: Tree = EmptyTree, pickleParams: => Unit = ()) = { - assert(symRefs(sym) == NoAddr) - registerDef(sym) - writeByte(tag) - withLength { - pickleName(sym) - pickleParams - tpt match { - case tpt: TypeTree => pickleTpt(tpt) - case _ => pickleTree(tpt) - } - pickleTreeUnlessEmpty(rhs) - pickleModifiers(sym) - } - } + 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)) - def pickleParam(tree: Tree): 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 pickleModifiers(sym: Symbol)(implicit ctx: Context): Unit = { + import Flags._ + val flags = sym.flags + val privateWithin = sym.privateWithin + if (privateWithin.exists) { + writeByte(if (flags is Protected) PROTECTEDqualified else PRIVATEqualified) + pickleType(privateWithin.typeRef) } - - def pickleParams(trees: List[Tree]): Unit = { - trees.foreach(preRegister) - trees.foreach(pickleParam) + if (flags is Private) writeByte(PRIVATE) + if (flags is Protected) if (!privateWithin.exists) writeByte(PROTECTED) + if ((flags is Final) && !(sym is Module)) writeByte(FINAL) + if (flags is Case) writeByte(CASE) + if (flags is Override) writeByte(OVERRIDE) + if (flags is Inline) writeByte(INLINE) + if (flags is JavaStatic) writeByte(STATIC) + if (flags is Module) writeByte(OBJECT) + if (flags is Local) writeByte(LOCAL) + if (flags is Synthetic) writeByte(SYNTHETIC) + if (flags is Artifact) writeByte(ARTIFACT) + if (flags is Scala2x) writeByte(SCALA2X) + if (flags is InSuperCall) writeByte(INSUPERCALL) + if (sym.isTerm) { + if (flags is Implicit) writeByte(IMPLICIT) + if ((flags is Lazy) && !(sym is Module)) writeByte(LAZY) + if (flags is AbsOverride) { writeByte(ABSTRACT); writeByte(OVERRIDE) } + if (flags is Mutable) writeByte(MUTABLE) + if (flags is Accessor) writeByte(FIELDaccessor) + if (flags is CaseAccessor) writeByte(CASEaccessor) + if (flags is DefaultParameterized) writeByte(DEFAULTparameterized) + if (flags is Stable) writeByte(STABLE) + } else { + if (flags is Sealed) writeByte(SEALED) + if (flags is Abstract) writeByte(ABSTRACT) + if (flags is Trait) writeByte(TRAIT) + if (flags is Covariant) writeByte(COVARIANT) + if (flags is Contravariant) writeByte(CONTRAVARIANT) } + sym.annotations.foreach(pickleAnnotation) + } - def pickleStats(stats: List[Tree]) = { - stats.foreach(preRegister) - stats.foreach(stat => if (!stat.isEmpty) pickleTree(stat)) - } + def pickleAnnotation(ann: Annotation)(implicit ctx: Context) = { + writeByte(ANNOTATION) + withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) } + } - def pickleModifiers(sym: Symbol): Unit = { - import Flags._ - val flags = sym.flags - val privateWithin = sym.privateWithin - if (privateWithin.exists) { - writeByte(if (flags is Protected) PROTECTEDqualified else PRIVATEqualified) - pickleType(privateWithin.typeRef) - } - if (flags is Private) writeByte(PRIVATE) - if (flags is Protected) if (!privateWithin.exists) writeByte(PROTECTED) - if ((flags is Final) && !(sym is Module)) writeByte(FINAL) - if (flags is Case) writeByte(CASE) - if (flags is Override) writeByte(OVERRIDE) - if (flags is Inline) writeByte(INLINE) - if (flags is JavaStatic) writeByte(STATIC) - if (flags is Module) writeByte(OBJECT) - if (flags is Local) writeByte(LOCAL) - if (flags is Synthetic) writeByte(SYNTHETIC) - if (flags is Artifact) writeByte(ARTIFACT) - if (flags is Scala2x) writeByte(SCALA2X) - if (flags is InSuperCall) writeByte(INSUPERCALL) - if (sym.isTerm) { - if (flags is Implicit) writeByte(IMPLICIT) - if ((flags is Lazy) && !(sym is Module)) writeByte(LAZY) - if (flags is AbsOverride) { writeByte(ABSTRACT); writeByte(OVERRIDE) } - if (flags is Mutable) writeByte(MUTABLE) - if (flags is Accessor) writeByte(FIELDaccessor) - if (flags is CaseAccessor) writeByte(CASEaccessor) - if (flags is DefaultParameterized) writeByte(DEFAULTparameterized) - if (flags is Stable) writeByte(STABLE) - } else { - if (flags is Sealed) writeByte(SEALED) - if (flags is Abstract) writeByte(ABSTRACT) - if (flags is Trait) writeByte(TRAIT) - if (flags is Covariant) writeByte(COVARIANT) - if (flags is Contravariant) writeByte(CONTRAVARIANT) - } - sym.annotations.foreach(pickleAnnotation) - } + def pickle(trees: List[Tree])(implicit ctx: Context) = { + trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree)) + assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %") + } - def pickleAnnotation(ann: Annotation) = { - writeByte(ANNOTATION) - withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) } - } + def compactify() = { + buf.compactify() + assert(forwardSymRefs.isEmpty, s"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %") def updateMapWithDeltas[T](mp: collection.mutable.Map[T, Addr]) = for (key <- mp.keysIterator.toBuffer[T]) mp(key) = adjusted(mp(key)) - trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree)) - assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %") - compactify() updateMapWithDeltas(symRefs) } } diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index eadccb2a3..81d19f7e4 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -10,7 +10,8 @@ import ast.{tpd, Trees, untpd} import Trees._ import Decorators._ import TastyUnpickler._, TastyBuffer._, PositionPickler._ -import annotation.switch +import scala.annotation.{tailrec, switch} +import scala.collection.mutable.ListBuffer import scala.collection.{ mutable, immutable } import typer.Mode import config.Printers.pickling @@ -65,7 +66,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { def unpickle()(implicit ctx: Context): List[Tree] = { assert(roots != null, "unpickle without previous enterTopLevel") val stats = new TreeReader(reader) - .readIndexedStats(NoSymbol, reader.endAddr)(ctx.addMode(Mode.AllowDependentFunctions)) + .readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions)) normalizePos(stats, totalRange) stats } @@ -676,6 +677,29 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { .withType(localDummy.nonMemberTermRef)) } + def skipToplevel()(implicit ctx: Context): Unit= { + if (!isAtEnd) + nextByte match { + case IMPORT | PACKAGE => + skipTree() + skipToplevel() + case _ => + } + } + + def readTopLevel()(implicit ctx: Context): List[Tree] = { + @tailrec def read(acc: ListBuffer[Tree]): List[Tree] = nextByte match { + case IMPORT | PACKAGE => + acc += readIndexedStat(NoSymbol) + if (!isAtEnd) + read(acc) + else acc.toList + case _ => // top-level trees which are not imports or packages are not part of tree + acc.toList + } + read(new ListBuffer[tpd.Tree]) + } + def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match { case TYPEDEF | VALDEF | DEFDEF => readIndexedDef() diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index 0d9bdcc3c..8040c86d4 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -44,7 +44,7 @@ class Pickler extends Phase { if (ctx.settings.YtestPickler.value) beforePickling(cls) = tree.show val pickler = new TastyPickler() unit.picklers += (cls -> pickler) - val treePkl = new TreePickler(pickler) + val treePkl = pickler.treePkl treePkl.pickle(tree :: Nil) pickler.addrOfTree = treePkl.buf.addrOfTree pickler.addrOfSym = treePkl.addrOfSym |