aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/tasty/TreePickler.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-11-14 11:58:59 +0100
committerMartin Odersky <odersky@gmail.com>2016-11-16 14:25:40 +0100
commitfe20b9064fca765a38345a09aa484bfb537aa3c0 (patch)
tree99cce659b7c2fe7d79fd5c9c87ba51bcb96a7545 /src/dotty/tools/dotc/core/tasty/TreePickler.scala
parent97b6985c34915b58e0c81fbab464f4bd532c27d0 (diff)
downloaddotty-fe20b9064fca765a38345a09aa484bfb537aa3c0.tar.gz
dotty-fe20b9064fca765a38345a09aa484bfb537aa3c0.tar.bz2
dotty-fe20b9064fca765a38345a09aa484bfb537aa3c0.zip
Pickle and unpickle type trees
Lots of other changes to make positions work out everywhere. One important change is that now trees can be shared, just as types can. This change improves memory requirements (a bit) and also makes positions in shared trees more robust.
Diffstat (limited to 'src/dotty/tools/dotc/core/tasty/TreePickler.scala')
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala387
1 files changed, 214 insertions, 173 deletions
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 98a369f25..1838bc5bb 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -10,6 +10,7 @@ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annot
import collection.mutable
import typer.Inliner
import NameOps._
+import StdNames.nme
import TastyBuffer._
import TypeApplications._
@@ -153,11 +154,6 @@ 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)
@@ -249,7 +245,7 @@ class TreePickler(pickler: TastyPickler) {
writeByte(TYPEBOUNDS)
withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) }
case tpe: AnnotatedType =>
- writeByte(ANNOTATED)
+ writeByte(ANNOTATEDtype)
withLength { pickleType(tpe.tpe, richTypes); pickleTree(tpe.annot.tree) }
case tpe: AndOrType =>
writeByte(if (tpe.isAnd) ANDtype else ORtype)
@@ -306,7 +302,7 @@ class TreePickler(pickler: TastyPickler) {
}
def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit =
- pickleTypeWithPos(tpt.tpe, tpt) // TODO correlate with original when generating positions
+ pickleTree(tpt)
def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit =
if (!tree.isEmpty) pickleTree(tree)
@@ -346,181 +342,226 @@ class TreePickler(pickler: TastyPickler) {
stats.foreach(stat => if (!stat.isEmpty) pickleTree(stat))
}
- def pickleTree(tree: Tree)(implicit ctx: Context): Unit = try {
- registerTreeAddr(tree)
- tree match {
- case tree if tree.isType =>
- pickleTpt(tree)
- case Ident(name) =>
- tree.tpe match {
- case tp: TermRef => pickleType(tp)
- case _ =>
- writeByte(IDENT)
- pickleName(name)
- pickleType(tree.tpe)
- }
- case This(_) =>
- pickleType(tree.tpe)
- case Select(qual, name) =>
- writeByte(SELECT)
- val realName = tree.tpe match {
- case tp: NamedType if tp.name.isShadowedName => tp.name
- case _ => name
- }
- val sig = tree.tpe.signature
- if (sig == Signature.NotAMethod) pickleName(realName)
- else pickleNameAndSig(realName, sig)
- pickleTree(qual)
- case Apply(fun, args) =>
- writeByte(APPLY)
- withLength {
- pickleTree(fun)
- args.foreach(pickleTree)
- }
- case TypeApply(fun, args) =>
- writeByte(TYPEAPPLY)
- withLength {
- pickleTree(fun)
- args.foreach(pickleTpt)
- }
- case Literal(const1) =>
- pickleConstant {
+ def pickleTree(tree: Tree)(implicit ctx: Context): Unit = {
+ val addr = registerTreeAddr(tree)
+ if (addr != currentAddr) {
+ writeByte(SHARED)
+ writeRef(addr)
+ }
+ else
+ try tree match {
+ case Ident(name) =>
tree.tpe match {
- case ConstantType(const2) => const2
- case _ => const1
+ case tp: TermRef if name != nme.WILDCARD =>
+ // wildcards are pattern bound, need to be preserved as ids.
+ pickleType(tp)
+ case _ =>
+ writeByte(if (tree.isType) IDENTtpt else IDENT)
+ pickleName(name)
+ pickleType(tree.tpe)
}
- }
- case Super(qual, mix) =>
- writeByte(SUPER)
- withLength {
- pickleTree(qual);
- if (!mix.isEmpty) {
- val SuperType(_, mixinType) = tree.tpe
- pickleType(mixinType)
+ case This(_) =>
+ pickleType(tree.tpe)
+ case Select(qual, name) =>
+ writeByte(if (name.isTypeName) SELECTtpt else SELECT)
+ val realName = tree.tpe match {
+ case tp: NamedType if tp.name.isShadowedName => tp.name
+ case _ => name
}
- }
- case New(tpt) =>
- writeByte(NEW)
- pickleTpt(tpt)
- case Typed(expr, tpt) =>
- writeByte(TYPED)
- withLength { pickleTree(expr); pickleTpt(tpt) }
- case NamedArg(name, arg) =>
- writeByte(NAMEDARG)
- withLength { pickleName(name); pickleTree(arg) }
- case Assign(lhs, rhs) =>
- writeByte(ASSIGN)
- withLength { pickleTree(lhs); pickleTree(rhs) }
- case Block(stats, expr) =>
- writeByte(BLOCK)
- stats.foreach(preRegister)
- withLength { pickleTree(expr); stats.foreach(pickleTree) }
- case If(cond, thenp, elsep) =>
- writeByte(IF)
- withLength{ pickleTree(cond); pickleTree(thenp); pickleTree(elsep) }
- case Closure(env, meth, tpt) =>
- writeByte(LAMBDA)
- assert(env.isEmpty)
- withLength{
- pickleTree(meth)
- if (tpt.tpe.exists) pickleTpt(tpt)
- }
- case Match(selector, cases) =>
- writeByte(MATCH)
- withLength { pickleTree(selector); cases.foreach(pickleTree) }
- case CaseDef(pat, guard, rhs) =>
- writeByte(CASEDEF)
- withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) }
- case Return(expr, from) =>
- writeByte(RETURN)
- withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) }
- case Try(block, cases, finalizer) =>
- writeByte(TRY)
- withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) }
- case SeqLiteral(elems, elemtpt) =>
- writeByte(REPEATED)
- withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
- 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)
- withLength { pickleName(name); pickleType(tree.symbol.info); pickleTree(body) }
- case Alternative(alts) =>
- writeByte(ALTERNATIVE)
- withLength { alts.foreach(pickleTree) }
- case UnApply(fun, implicits, patterns) =>
- writeByte(UNAPPLY)
- withLength {
- pickleTree(fun)
- for (implicitArg <- implicits) {
- writeByte(IMPLICITarg)
- pickleTree(implicitArg)
+ val sig = tree.tpe.signature
+ if (sig == Signature.NotAMethod) pickleName(realName)
+ else pickleNameAndSig(realName, sig)
+ pickleTree(qual)
+ case Apply(fun, args) =>
+ writeByte(APPLY)
+ withLength {
+ pickleTree(fun)
+ args.foreach(pickleTree)
}
- pickleType(tree.tpe)
- patterns.foreach(pickleTree)
- }
- case tree: ValDef =>
- pickleDef(VALDEF, tree.symbol, tree.tpt, tree.rhs)
- case tree: DefDef =>
- def pickleAllParams = {
- pickleParams(tree.tparams)
- for (vparams <- tree.vparamss) {
- writeByte(PARAMS)
- withLength { pickleParams(vparams) }
+ case TypeApply(fun, args) =>
+ writeByte(TYPEAPPLY)
+ withLength {
+ pickleTree(fun)
+ args.foreach(pickleTpt)
}
- }
- pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams)
- case tree: TypeDef =>
- pickleDef(TYPEDEF, tree.symbol, tree.rhs)
- case tree: Template =>
- registerDef(tree.symbol)
- writeByte(TEMPLATE)
- val (params, rest) = tree.body partition {
- case stat: TypeDef => stat.symbol is Flags.Param
- case stat: ValOrDefDef =>
- stat.symbol.is(Flags.ParamAccessor) && !stat.symbol.isSetter
- case _ => false
- }
- withLength {
- pickleParams(params)
- tree.parents.foreach(pickleTree)
- val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info
- 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
- case tp: Type => tp
+ case Literal(const1) =>
+ pickleConstant {
+ tree.tpe match {
+ case ConstantType(const2) => const2
+ case _ => const1
+ }
+ }
+ case Super(qual, mix) =>
+ writeByte(SUPER)
+ withLength {
+ pickleTree(qual);
+ if (!mix.isEmpty) {
+ val SuperType(_, mixinType) = tree.tpe
+ pickleType(mixinType)
+ }
+ }
+ case New(tpt) =>
+ writeByte(NEW)
+ pickleTpt(tpt)
+ case Typed(expr, tpt) =>
+ writeByte(TYPED)
+ withLength { pickleTree(expr); pickleTpt(tpt) }
+ case NamedArg(name, arg) =>
+ writeByte(NAMEDARG)
+ withLength { pickleName(name); pickleTree(arg) }
+ case Assign(lhs, rhs) =>
+ writeByte(ASSIGN)
+ withLength { pickleTree(lhs); pickleTree(rhs) }
+ case Block(stats, expr) =>
+ writeByte(BLOCK)
+ stats.foreach(preRegister)
+ withLength { pickleTree(expr); stats.foreach(pickleTree) }
+ case If(cond, thenp, elsep) =>
+ writeByte(IF)
+ withLength { pickleTree(cond); pickleTree(thenp); pickleTree(elsep) }
+ case Closure(env, meth, tpt) =>
+ writeByte(LAMBDA)
+ assert(env.isEmpty)
+ withLength {
+ pickleTree(meth)
+ if (tpt.tpe.exists) pickleTpt(tpt)
+ }
+ case Match(selector, cases) =>
+ writeByte(MATCH)
+ withLength { pickleTree(selector); cases.foreach(pickleTree) }
+ case CaseDef(pat, guard, rhs) =>
+ writeByte(CASEDEF)
+ withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) }
+ case Return(expr, from) =>
+ writeByte(RETURN)
+ withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) }
+ case Try(block, cases, finalizer) =>
+ writeByte(TRY)
+ withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) }
+ case SeqLiteral(elems, elemtpt) =>
+ writeByte(REPEATED)
+ withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
+ 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)
+ withLength { pickleName(name); pickleType(tree.symbol.info); pickleTree(body) }
+ case Alternative(alts) =>
+ writeByte(ALTERNATIVE)
+ withLength { alts.foreach(pickleTree) }
+ case UnApply(fun, implicits, patterns) =>
+ writeByte(UNAPPLY)
+ withLength {
+ pickleTree(fun)
+ for (implicitArg <- implicits) {
+ writeByte(IMPLICITarg)
+ pickleTree(implicitArg)
+ }
+ pickleType(tree.tpe)
+ patterns.foreach(pickleTree)
+ }
+ case tree: ValDef =>
+ pickleDef(VALDEF, tree.symbol, tree.tpt, tree.rhs)
+ case tree: DefDef =>
+ def pickleAllParams = {
+ pickleParams(tree.tparams)
+ for (vparams <- tree.vparamss) {
+ writeByte(PARAMS)
+ withLength { pickleParams(vparams) }
+ }
+ }
+ pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams)
+ case tree: TypeDef =>
+ pickleDef(TYPEDEF, tree.symbol, tree.rhs)
+ case tree: Template =>
+ registerDef(tree.symbol)
+ writeByte(TEMPLATE)
+ val (params, rest) = tree.body partition {
+ case stat: TypeDef => stat.symbol is Flags.Param
+ case stat: ValOrDefDef =>
+ stat.symbol.is(Flags.ParamAccessor) && !stat.symbol.isSetter
+ case _ => false
+ }
+ withLength {
+ pickleParams(params)
+ tree.parents.foreach(pickleTree)
+ val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info
+ if ((selfInfo ne NoType) || !tree.self.isEmpty) {
+ writeByte(SELFDEF)
+ pickleName(tree.self.name)
+
+ if (!tree.self.tpt.isEmpty) pickleTree(tree.self.tpt)
+ else {
+ if (!tree.self.isEmpty) registerTreeAddr(tree.self)
+ pickleType {
+ cinfo.selfInfo match {
+ case sym: Symbol => sym.info
+ case tp: Type => tp
+ }
+ }
}
}
+ pickleStats(tree.constr :: rest)
}
- pickleStats(tree.constr :: rest)
- }
- case Import(expr, selectors) =>
- writeByte(IMPORT)
- withLength {
- pickleTree(expr)
- selectors foreach {
- case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) =>
- pickleSelector(IMPORTED, from)
- pickleSelector(RENAMED, to)
- case id @ Ident(_) =>
- pickleSelector(IMPORTED, id)
+ case Import(expr, selectors) =>
+ writeByte(IMPORT)
+ withLength {
+ pickleTree(expr)
+ selectors foreach {
+ case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) =>
+ pickleSelector(IMPORTED, from)
+ pickleSelector(RENAMED, to)
+ case id @ Ident(_) =>
+ pickleSelector(IMPORTED, id)
+ }
}
- }
- case PackageDef(pid, stats) =>
- writeByte(PACKAGE)
- withLength { pickleType(pid.tpe); pickleStats(stats) }
- }}
- catch {
- case ex: AssertionError =>
- println(i"error when pickling tree $tree")
- throw ex
+ case PackageDef(pid, stats) =>
+ writeByte(PACKAGE)
+ withLength { pickleType(pid.tpe); pickleStats(stats) }
+ case tree: TypeTree =>
+ pickleType(tree.tpe)
+ case SingletonTypeTree(ref) =>
+ writeByte(SINGLETONtpt)
+ pickleTree(ref)
+ case RefinedTypeTree(parent, refinements) =>
+ if (refinements.isEmpty) pickleTree(parent)
+ else {
+ val refineCls = refinements.head.symbol.owner.asClass
+ pickledTypes.put(refineCls.typeRef, currentAddr)
+ writeByte(REFINEDtpt)
+ refinements.foreach(preRegister)
+ withLength { pickleTree(parent); refinements.foreach(pickleTree) }
+ }
+ case AppliedTypeTree(tycon, args) =>
+ writeByte(APPLIEDtpt)
+ withLength { pickleTree(tycon); args.foreach(pickleTree(_)) }
+ case AndTypeTree(tp1, tp2) =>
+ writeByte(ANDtpt)
+ withLength { pickleTree(tp1); pickleTree(tp2) }
+ case OrTypeTree(tp1, tp2) =>
+ writeByte(ORtpt)
+ withLength { pickleTree(tp1); pickleTree(tp2) }
+ case ByNameTypeTree(tp) =>
+ writeByte(BYNAMEtpt)
+ pickleTree(tp)
+ case Annotated(tree, annot) =>
+ writeByte(ANNOTATEDtpt)
+ withLength { pickleTree(tree); pickleTree(annot.tree) }
+ case PolyTypeTree(tparams, body) =>
+ writeByte(POLYtpt)
+ withLength { pickleParams(tparams); pickleTree(body) }
+ case TypeBoundsTree(lo, hi) =>
+ writeByte(TYPEBOUNDStpt)
+ withLength { pickleTree(lo); pickleTree(hi) }
+ }
+ catch {
+ case ex: AssertionError =>
+ println(i"error when pickling tree $tree")
+ throw ex
+ }
}
def pickleSelector(tag: Int, id: untpd.Ident)(implicit ctx: Context): Unit = {