aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--docs/syntax-summary.txt4
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala10
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala8
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionPickler.scala26
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala142
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyPickler.scala2
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeBuffer.scala24
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala387
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala114
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala7
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala55
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala4
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala2
-rw-r--r--tests/pickling/annot.scala12
-rw-r--r--tests/pickling/pickleTypes.scala13
-rw-r--r--tests/pickling/simple.scala6
16 files changed, 502 insertions, 314 deletions
diff --git a/docs/syntax-summary.txt b/docs/syntax-summary.txt
index 0a52ec802..04e149de6 100644
--- a/docs/syntax-summary.txt
+++ b/docs/syntax-summary.txt
@@ -160,7 +160,7 @@ grammar.
SimpleExpr1 ::= Literal
| Path
| `_'
- | `(' ExprsInParens `)' Parens(exprs)
+ | `(' ExprsInParens2 `)' Parens(exprs)
| SimpleExpr `.' id Select(expr, id)
| SimpleExpr (TypeArgs | NamedTypeArgs) TypeApply(expr, args)
| SimpleExpr1 ArgumentExprs Apply(expr, args)
@@ -210,7 +210,7 @@ grammar.
| SimplePattern1 `.' id
PatVar ::= varid
| `_'
- Patterns ::= Pattern [`,' Pattern]
+ Patterns ::= Pattern {`,' Pattern}
ArgumentPatterns ::= `(' [Patterns] `)' Apply(fn, pats)
| `(' [Patterns `,'] Pattern2 `:' `_' `*' ')
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index db2ce5649..09f2099d2 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -133,7 +133,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def OrTypeTree(left: Tree, right: Tree)(implicit ctx: Context): OrTypeTree =
ta.assignType(untpd.OrTypeTree(left, right), left, right)
- // RefinedTypeTree is missing, handled specially in Typer and Unpickler.
+ def RefinedTypeTree(parent: Tree, refinements: List[Tree], refineCls: ClassSymbol)(implicit ctx: Context): Tree =
+ ta.assignType(untpd.RefinedTypeTree(parent, refinements), parent, refinements, refineCls)
def AppliedTypeTree(tycon: Tree, args: List[Tree])(implicit ctx: Context): AppliedTypeTree =
ta.assignType(untpd.AppliedTypeTree(tycon, args), tycon, args)
@@ -141,6 +142,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def ByNameTypeTree(result: Tree)(implicit ctx: Context): ByNameTypeTree =
ta.assignType(untpd.ByNameTypeTree(result), result)
+ def PolyTypeTree(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): PolyTypeTree =
+ ta.assignType(untpd.PolyTypeTree(tparams, body), tparams, body)
+
def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree =
ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi)
@@ -306,8 +310,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case _ =>
false
}
- typeIsElidable ||
- tp.symbol.is(JavaStatic) ||
+ typeIsElidable ||
+ tp.symbol.is(JavaStatic) ||
tp.symbol.hasAnnotation(defn.ScalaStaticAnnot)
}
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 62fa2d07d..7b51a58d1 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -633,9 +633,9 @@ class Definitions {
name.startsWith(prefix) && name.drop(prefix.length).forall(_.isDigit)
}
- def isBottomClass(cls: Symbol) =
+ def isBottomClass(cls: Symbol) =
cls == NothingClass || cls == NullClass
- def isBottomType(tp: Type) =
+ def isBottomType(tp: Type) =
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)
def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function)
@@ -785,8 +785,8 @@ class Definitions {
if (!_isInitialized) {
// force initialization of every symbol that is synthesized or hijacked by the compiler
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
-
- // Enter all symbols from the scalaShadowing package in the scala package
+
+ // Enter all symbols from the scalaShadowing package in the scala package
for (m <- ScalaShadowingPackageClass.info.decls)
ScalaPackageClass.enter(m)
diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
index 4b67bc188..546894a9e 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
@@ -13,7 +13,7 @@ import collection.mutable
import TastyBuffer._
import util.Positions._
-class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]) {
+class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) {
val buf = new TastyBuffer(5000)
pickler.newSection("Positions", buf)
import buf._
@@ -21,21 +21,6 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]
private val remainingAddrs = new java.util.IdentityHashMap[Tree, Iterator[Addr]]
- def nextTreeAddr(tree: Tree): Option[Addr] = remainingAddrs.get(tree) match {
- case null =>
- addrsOfTree(tree) match {
- case Nil =>
- None
- case addr :: Nil =>
- Some(addr)
- case addrs =>
- remainingAddrs.put(tree, addrs.iterator)
- nextTreeAddr(tree)
- }
- case it: Iterator[_] =>
- if (it.hasNext) Some(it.next) else None
- }
-
def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean) = {
def toInt(b: Boolean) = if (b) 1 else 0
(addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
@@ -60,8 +45,7 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]
*/
def alwaysNeedsPos(x: Positioned) = x match {
case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field
- | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
- case x: Trees.Tree[_] => x.isType // types are unpickled as TypeTrees, so child positions are not available
+ | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
case _ => false
}
@@ -69,7 +53,7 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]
case x: Tree @unchecked =>
val pos = if (x.isInstanceOf[MemberDef]) x.pos else x.pos.toSynthetic
if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) {
- nextTreeAddr(x) match {
+ addrOfTree(x) match {
case Some(addr) =>
//println(i"pickling $x with $pos at $addr")
pickleDeltas(addr.index, pos)
@@ -79,13 +63,15 @@ class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]
}
//else if (x.pos.exists) println(i"skipping $x")
x match {
- case x: MemberDef @unchecked =>
+ case x: MemberDef @unchecked =>
for (ann <- x.symbol.annotations) traverse(ann.tree)
case _ =>
}
traverse(x.productIterator)
case xs: TraversableOnce[_] =>
xs.foreach(traverse)
+ case x: Annotation =>
+ traverse(x.tree)
case _ =>
}
traverse(roots)
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index f9743d9d2..80bd39841 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -71,7 +71,7 @@ Standard-Section: "ASTs" TopLevelStat*
Term = Path
Application
- IDENT NameRef Type // used when ident’s type is not a TermRef
+ IDENT NameRef Type // used when term ident’s type is not a TermRef
SELECT possiblySigned_NameRef qual_Term
NEW cls_Type
SUPER Length this_Term mixinTrait_Type?
@@ -89,6 +89,17 @@ Standard-Section: "ASTs" TopLevelStat*
BIND Length boundName_NameRef patType_Type pat_Term
ALTERNATIVE Length alt_Term*
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term*
+ IDENTtpt NameRef Type // used when type ident's type is not a TypeRef
+ SELECTtpt NameRef qual_Term
+ SINGLETONtpt Path
+ REFINDtpt Length underlying_Term refinement_Stat*
+ APPLIEDtpt Length tycon_Term arg_Term*
+ POLYtpt Length TypeParam* body_Term
+ TYPEBOUNDStpt Length low_Term high_Term
+ ANNOTATEDtpt Length underlying_Term fullAnnotation_Term
+ ANDtpt Length left_Term right_Term
+ ORtpt Length left_Term right_Term
+ BYNAMEtpt underlying_Term
EMPTYTREE
SHARED term_ASTRef
Application = APPLY Length fn_Term arg_Term*
@@ -133,7 +144,7 @@ Standard-Section: "ASTs" TopLevelStat*
APPLIEDtype Length tycon_Type arg_Type*
TYPEBOUNDS Length low_Type high_Type
TYPEALIAS Length alias_Type (COVARIANT | CONTRAVARIANT)?
- ANNOTATED Length underlying_Type fullAnnotation_Term
+ ANNOTATEDtype Length underlying_Type fullAnnotation_Term
ANDtype Length left_Type right_Type
ORtype Length left_Type right_Type
BIND Length boundName_NameRef bounds_Type
@@ -271,19 +282,23 @@ object TastyFormat {
final val CLASSconst = 97
final val ENUMconst = 98
final val BYNAMEtype = 99
- final val NEW = 100
- final val IMPLICITarg = 101
- final val PRIVATEqualified = 102
- final val PROTECTEDqualified = 103
- final val RECtype = 104
+ final val BYNAMEtpt = 100
+ final val NEW = 101
+ final val IMPLICITarg = 102
+ final val PRIVATEqualified = 103
+ final val PROTECTEDqualified = 104
+ final val RECtype = 105
+ final val SINGLETONtpt = 106
final val IDENT = 112
- final val SELECT = 113
- final val TERMREFsymbol = 114
- final val TERMREF = 115
- final val TYPEREFsymbol = 116
- final val TYPEREF = 117
- final val SELFDEF = 118
+ final val IDENTtpt = 113
+ final val SELECT = 114
+ final val SELECTtpt = 115
+ final val TERMREFsymbol = 116
+ final val TERMREF = 117
+ final val TYPEREFsymbol = 118
+ final val TYPEREF = 119
+ final val SELFDEF = 120
final val PACKAGE = 128
final val VALDEF = 129
@@ -293,39 +308,44 @@ object TastyFormat {
final val TYPEPARAM = 133
final val PARAMS = 134
final val PARAM = 136
-
- final val APPLY = 139
- final val TYPEAPPLY = 140
-
- final val TYPED = 143
- final val NAMEDARG = 144
- final val ASSIGN = 145
- final val BLOCK = 146
- final val IF = 147
- final val LAMBDA = 148
- final val MATCH = 149
- final val RETURN = 150
- final val TRY = 151
- final val INLINED = 152
- final val REPEATED = 153
- final val BIND = 154
- final val ALTERNATIVE = 155
- final val UNAPPLY = 156
- final val ANNOTATED = 157
- final val CASEDEF = 158
- final val TEMPLATE = 160
- final val SUPER = 163
- final val SUPERtype = 166
- final val REFINEDtype = 167
- final val APPLIEDtype = 168
- final val TYPEBOUNDS = 169
- final val TYPEALIAS = 170
- final val ANDtype = 171
- final val ORtype = 172
- final val METHODtype = 174
- final val POLYtype = 175
- final val PARAMtype = 176
- final val ANNOTATION = 177
+ final val APPLY = 137
+ final val TYPEAPPLY = 138
+ final val TYPED = 139
+ final val NAMEDARG = 140
+ final val ASSIGN = 141
+ final val BLOCK = 142
+ final val IF = 143
+ final val LAMBDA = 144
+ final val MATCH = 145
+ final val RETURN = 146
+ final val TRY = 147
+ final val INLINED = 148
+ final val REPEATED = 149
+ final val BIND = 150
+ final val ALTERNATIVE = 151
+ final val UNAPPLY = 152
+ final val ANNOTATEDtype = 153
+ final val ANNOTATEDtpt = 154
+ final val CASEDEF = 155
+ final val TEMPLATE = 156
+ final val SUPER = 157
+ final val SUPERtype = 158
+ final val REFINEDtype = 159
+ final val REFINEDtpt = 160
+ final val APPLIEDtype = 161
+ final val APPLIEDtpt = 162
+ final val TYPEBOUNDS = 163
+ final val TYPEBOUNDStpt = 164
+ final val TYPEALIAS = 165
+ final val ANDtype = 166
+ final val ANDtpt = 167
+ final val ORtype = 168
+ final val ORtpt = 169
+ final val METHODtype = 170
+ final val POLYtype = 171
+ final val POLYtpt = 172
+ final val PARAMtype = 173
+ final val ANNOTATION = 174
final val firstSimpleTreeTag = UNITconst
final val firstNatTreeTag = SHARED
@@ -367,7 +387,22 @@ object TastyFormat {
| PRIVATEqualified
| PROTECTEDqualified => true
case _ => false
- }
+ }
+
+ def isTypeTreeTag(tag: Int) = tag match {
+ case IDENTtpt
+ | SELECTtpt
+ | SINGLETONtpt
+ | REFINEDtpt
+ | APPLIEDtpt
+ | POLYtpt
+ | TYPEBOUNDStpt
+ | ANNOTATEDtpt
+ | ANDtpt
+ | ORtpt
+ | BYNAMEtpt => true
+ case _ => false
+ }
def nameTagToString(tag: Int): String = tag match {
case UTF8 => "UTF8"
@@ -429,7 +464,9 @@ object TastyFormat {
case RECtype => "RECtype"
case IDENT => "IDENT"
+ case IDENTtpt => "IDENTtpt"
case SELECT => "SELECT"
+ case SELECTtpt => "SELECTtpt"
case TERMREFsymbol => "TERMREFsymbol"
case TERMREF => "TERMREF"
case TYPEREFsymbol => "TYPEREFsymbol"
@@ -462,7 +499,8 @@ object TastyFormat {
case BIND => "BIND"
case ALTERNATIVE => "ALTERNATIVE"
case UNAPPLY => "UNAPPLY"
- case ANNOTATED => "ANNOTATED"
+ case ANNOTATEDtype => "ANNOTATEDtype"
+ case ANNOTATEDtpt => "ANNOTATEDtpt"
case CASEDEF => "CASEDEF"
case IMPLICITarg => "IMPLICITarg"
case TEMPLATE => "TEMPLATE"
@@ -471,15 +509,23 @@ object TastyFormat {
case SUPER => "SUPER"
case CLASSconst => "CLASSconst"
case ENUMconst => "ENUMconst"
+ case SINGLETONtpt => "SINGLETONtpt"
case SUPERtype => "SUPERtype"
case REFINEDtype => "REFINEDtype"
+ case REFINEDtpt => "REFINEDtpt"
case APPLIEDtype => "APPLIEDtype"
+ case APPLIEDtpt => "APPLIEDtpt"
case TYPEBOUNDS => "TYPEBOUNDS"
+ case TYPEBOUNDStpt => "TYPEBOUNDStpt"
case TYPEALIAS => "TYPEALIAS"
case ANDtype => "ANDtype"
+ case ANDtpt => "ANDtpt"
case ORtype => "ORtype"
+ case ORtpt => "ORtpt"
case BYNAMEtype => "BYNAMEtype"
+ case BYNAMEtpt => "BYNAMEtpt"
case POLYtype => "POLYtype"
+ case POLYtpt => "POLYtpt"
case METHODtype => "METHODtype"
case PARAMtype => "PARAMtype"
case ANNOTATION => "ANNOTATION"
diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
index f847dda68..55fe232c0 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
@@ -61,7 +61,7 @@ class TastyPickler {
* Note that a tree can have several addresses, if it is shared,
* i.e. accessible from different paths. Any such sharing is undone by pickling.
*/
- var addrsOfTree: tpd.Tree => List[Addr] = (_ => Nil)
+ var addrOfTree: tpd.Tree => Option[Addr] = (_ => None)
/**
* Addresses in TASTY file of symbols, stored by pickling.
diff --git a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
index f2681ecde..67dc6076f 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
@@ -17,26 +17,20 @@ class TreeBuffer extends TastyBuffer(50000) {
private var delta: Array[Int] = _
private var numOffsets = 0
- private type TreeAddrs = Any // really: Addr | List[Addr]
-
/** A map from trees to the address(es) at which a tree is pickled. There may be several
* such addresses if the tree is shared. To keep the map compact, the value type is a
* disjunction of a single address (which is the common case) and a list of addresses.
*/
- private val treeAddrs = new java.util.IdentityHashMap[Tree, TreeAddrs]
+ private val treeAddrs = new java.util.IdentityHashMap[Tree, Any] // really: Addr | Null
- def registerTreeAddr(tree: Tree) =
- treeAddrs.put(tree,
- treeAddrs.get(tree) match {
- case null => currentAddr
- case x: Addr => x :: currentAddr :: Nil
- case xs: List[_] => xs :+ currentAddr
- })
-
- def addrsOfTree(tree: Tree): List[Addr] = treeAddrs.get(tree) match {
- case null => Nil
- case addr: Addr => addr :: Nil
- case addrs: List[Addr] => addrs
+ def registerTreeAddr(tree: Tree): Addr = treeAddrs.get(tree) match {
+ case null => treeAddrs.put(tree, currentAddr); currentAddr
+ case addr: Addr => addr
+ }
+
+ def addrOfTree(tree: Tree): Option[Addr] = treeAddrs.get(tree) match {
+ case null => None
+ case addr: Addr => Some(addr)
}
private def offset(i: Int): Addr = Addr(offsets(i))
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 = {
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 90f718402..1f0bbca19 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -256,7 +256,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
else if (nextByte == CONTRAVARIANT) { readByte(); -1 }
else 0
TypeAlias(alias, variance)
- case ANNOTATED =>
+ case ANNOTATEDtype =>
AnnotatedType(readType(), Annotation(readTerm()))
case ANDtype =>
AndType(readType(), readType())
@@ -368,7 +368,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
private def readPackageRef()(implicit ctx: Context): TermSymbol = {
val name = readName()
- if (name == nme.ROOT) defn.RootPackage
+ if (name == nme.ROOT || name == nme.ROOTPKG) defn.RootPackage
else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageVal
else ctx.requiredPackage(name)
}
@@ -389,11 +389,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
if (owner.isClass) lctx.setScope(owner.unforcedDecls) else lctx.setNewScope
}
- private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbstractType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = {
+ private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbsType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = {
val lacksDefinition =
rhsIsEmpty &&
name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) ||
- isAbstractType
+ isAbsType
var flags = givenFlags
if (lacksDefinition && tag != PARAM) flags |= Deferred
if (tag == DEFDEF) flags |= Method
@@ -407,6 +407,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
flags
}
+ def isAbstractType(ttag: Int)(implicit ctx: Context): Boolean = nextUnsharedTag match {
+ case POLYtpt =>
+ val rdr = fork
+ rdr.reader.readByte() // tag
+ rdr.reader.readNat() // length
+ rdr.skipParams() // tparams
+ rdr.isAbstractType(rdr.nextUnsharedTag)
+ case TYPEBOUNDS | TYPEBOUNDStpt => true
+ case _ => false
+ }
+
/** Create symbol of definition node and enter in symAtAddr map
* @return the created symbol
*/
@@ -433,7 +444,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName
skipParams()
val ttag = nextUnsharedTag
- val isAbstractType = ttag == TYPEBOUNDS
+ val isAbsType = isAbstractType(ttag)
val isClass = ttag == TEMPLATE
val templateStart = currentAddr
skipTree() // tpt
@@ -447,7 +458,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
case _ => EmptyFlags
}
pickling.println(i"creating symbol $name at $start with flags $givenFlags")
- val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbstractType, rhsIsEmpty)
+ val flags = normalizeFlags(tag, givenFlags | nameFlags(rawName), name, isAbsType, rhsIsEmpty)
def adjustIfModule(completer: LazyType) =
if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer
val sym =
@@ -623,11 +634,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
val tag = readByte()
val end = readEnd()
- def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = {
- fork.indexParams(tag)(localContext(sym))
- readIndexedParams(tag)
- }
-
def readParamss(implicit ctx: Context): List[List[ValDef]] = {
collectWhile(nextByte == PARAMS) {
readByte()
@@ -849,9 +855,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readIndexedParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] =
collectWhile(nextByte == tag) { readIndexedDef().asInstanceOf[T] }
-// ------ Reading terms -----------------------------------------------------
+ def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = {
+ fork.indexParams(tag)
+ readIndexedParams(tag)
+ }
- def readTerm()(implicit ctx: Context): Tree = {
+// ------ Reading trees -----------------------------------------------------
+
+ def readTerm()(implicit ctx: Context): Tree = { // TODO: rename to readTree
val start = currentAddr
val tag = readByte()
pickling.println(s"reading term ${astTagToString(tag)} at $start")
@@ -859,34 +870,44 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readPathTerm(): Tree = {
goto(start)
readType() match {
+ case path: TypeRef => TypeTree(path)
case path: TermRef => ref(path)
case path: ThisType => This(path.cls)
case path: ConstantType => Literal(path.value)
}
}
+ def completeSelect(name: Name, tpf: Type => Type): Select = {
+ val localCtx =
+ if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx
+ val qual = readTerm()(localCtx)
+ val unshadowed = if (name.isShadowedName) name.revertShadowed else name
+ untpd.Select(qual, unshadowed).withType(tpf(qual.tpe.widenIfUnstable))
+ }
+
def readSimpleTerm(): Tree = tag match {
+ case SHARED =>
+ forkAt(readAddr()).readTerm()
case IDENT =>
untpd.Ident(readName()).withType(readType())
+ case IDENTtpt =>
+ untpd.Ident(readName().toTypeName).withType(readType())
case SELECT =>
- def readQual(name: Name) = {
- val localCtx =
- if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx
- readTerm()(localCtx)
- }
- def readRest(name: Name, sig: Signature) = {
- val unshadowed = if (name.isShadowedName) name.revertShadowed else name
- val qual = readQual(name)
- untpd.Select(qual, unshadowed)
- .withType(TermRef.withSig(qual.tpe.widenIfUnstable, name.asTermName, sig))
- }
+ def readRest(name: Name, sig: Signature) =
+ completeSelect(name, TermRef.withSig(_, name.asTermName, sig))
readNameSplitSig match {
case name: Name => readRest(name, Signature.NotAMethod)
case (name: Name, sig: Signature) => readRest(name, sig)
}
-
+ case SELECTtpt =>
+ val name = readName().toTypeName
+ completeSelect(name, TypeRef(_, name))
case NEW =>
New(readTpt())
+ case SINGLETONtpt =>
+ SingletonTypeTree(readTerm())
+ case BYNAMEtpt =>
+ ByNameTypeTree(readTpt())
case _ =>
readPathTerm()
}
@@ -894,10 +915,15 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readLengthTerm(): Tree = {
val end = readEnd()
+ def localNonClassCtx = {
+ val ctx1 = ctx.fresh.setNewScope
+ if (ctx.owner.isClass) ctx1.setOwner(ctx1.newLocalDummy(ctx.owner)) else ctx1
+ }
+
def readBlock(mkTree: (List[Tree], Tree) => Tree): Tree = {
val exprReader = fork
skipTree()
- val localCtx = ctx.fresh.setNewScope
+ val localCtx = localNonClassCtx
val stats = readStats(ctx.owner, end)(localCtx)
val expr = exprReader.readTerm()(localCtx)
mkTree(stats, expr)
@@ -937,7 +963,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
case BLOCK =>
readBlock(Block)
case INLINED =>
- val call = setPos(currentAddr, TypeTree(readType()))
+ val call = readTerm()
readBlock((defs, expr) => Inlined(call, defs.asInstanceOf[List[MemberDef]], expr))
case IF =>
If(readTerm(), readTerm(), readTerm())
@@ -974,6 +1000,28 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
val patType = readType()
val argPats = until(end)(readTerm())
UnApply(fn, implicitArgs, argPats, patType)
+ case REFINEDtpt =>
+ val refineCls = ctx.newCompleteClassSymbol(
+ ctx.owner, tpnme.REFINE_CLASS, Fresh, parents = Nil)
+ typeAtAddr(start) = refineCls.typeRef
+ val parent = readTpt()
+ val refinements = readStats(refineCls, end)(localContext(refineCls))
+ RefinedTypeTree(parent, refinements, refineCls)
+ case APPLIEDtpt =>
+ AppliedTypeTree(readTpt(), until(end)(readTpt()))
+ case ANDtpt =>
+ AndTypeTree(readTpt(), readTpt())
+ case ORtpt =>
+ OrTypeTree(readTpt(), readTpt())
+ case ANNOTATEDtpt =>
+ Annotated(readTpt(), readTerm())
+ case POLYtpt =>
+ val localCtx = localNonClassCtx
+ val tparams = readParams[TypeDef](TYPEPARAM)(localCtx)
+ val body = readTpt()(localCtx)
+ PolyTypeTree(tparams, body)
+ case TYPEBOUNDStpt =>
+ TypeBoundsTree(readTpt(), readTpt())
case _ =>
readPathTerm()
}
@@ -986,11 +1034,13 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
setPos(start, tree)
}
- def readTpt()(implicit ctx: Context) = {
- val start = currentAddr
- val tp = readType()
- if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree
- }
+ def readTpt()(implicit ctx: Context) =
+ if (isTypeTreeTag(nextUnsharedTag)) readTerm()
+ else {
+ val start = currentAddr
+ val tp = readType()
+ if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree
+ }
def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] =
collectWhile(nextByte == CASEDEF && currentAddr != end) { readCase()(ctx.fresh.setNewScope) }
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 785f57897..06d44e301 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -231,9 +231,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
protected def trimPrefix(text: Text) =
text.stripPrefix(objectPrefix).stripPrefix(packagePrefix)
- protected def selectionString(tp: NamedType) =
- if (tp.currentSymbol.exists) nameString(tp.symbol)
- else nameString(tp.name)
+ protected def selectionString(tp: NamedType) = {
+ val sym = if (homogenizedView) tp.symbol else tp.currentSymbol
+ if (sym.exists) nameString(sym) else nameString(tp.name)
+ }
/** The string representation of this type used as a prefix */
protected def toTextRef(tp: SingletonType): Text = controlled {
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 39a21b17b..4818c6eee 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -21,6 +21,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
/** A stack of enclosing DefDef, TypeDef, or ClassDef, or ModuleDefs nodes */
private var enclosingDef: untpd.Tree = untpd.EmptyTree
private var myCtx: Context = _ctx
+ private var printPos = ctx.settings.Yprintpos.value
override protected[this] implicit def ctx: Context = myCtx
def withEnclosingDef(enclDef: Tree[_ >: Untyped])(op: => Text): Text = {
@@ -35,6 +36,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
}
+ def inPattern(op: => Text): Text = {
+ val savedCtx = myCtx
+ myCtx = ctx.addMode(Mode.Pattern)
+ try op finally myCtx = savedCtx
+ }
+
+ def withoutPos(op: => Text): Text = {
+ val savedPrintPos = printPos
+ printPos = false
+ try op finally printPos = savedPrintPos
+ }
+
private def enclDefIsClass = enclosingDef match {
case owner: TypeDef[_] => owner.isClassDef
case owner: untpd.ModuleDef => true
@@ -134,6 +147,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
return toTextParents(tp.parentsWithArgs) ~ "{...}"
case JavaArrayType(elemtp) =>
return toText(elemtp) ~ "[]"
+ case tp: AnnotatedType if homogenizedView =>
+ withoutPos(super.toText(tp))
case tp: SelectionProto =>
return "?{ " ~ toText(tp.name) ~ (" " provided !tp.name.decode.last.isLetterOrDigit) ~
": " ~ toText(tp.memberProto) ~ " }"
@@ -249,7 +264,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
def nameIdText(tree: untpd.NameTree): Text =
- toText(tree.name) ~ idText(tree)
+ if (tree.hasType && tree.symbol.exists) nameString(tree.symbol)
+ else toText(tree.name) ~ idText(tree)
def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = {
val Template(constr @ DefDef(_, tparams, vparamss, _, _), parents, self, _) = impl
@@ -284,7 +300,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case tp: NamedType if name != nme.WILDCARD =>
val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix
toTextPrefix(pre) ~ selectionString(tp)
- case _ => toText(name)
+ case _ =>
+ toText(name)
}
case tree @ Select(qual, name) =>
if (qual.isType) toTextLocal(qual) ~ "#" ~ toText(name)
@@ -337,7 +354,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (sel.isEmpty) blockText(cases)
else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) }
case CaseDef(pat, guard, body) =>
- "case " ~ toText(pat) ~ optText(guard)(" if " ~ _) ~ " => " ~ caseBlockText(body)
+ "case " ~ inPattern(toText(pat)) ~ optText(guard)(" if " ~ _) ~ " => " ~ caseBlockText(body)
case Return(expr, from) =>
changePrec(GlobalPrec) { "return" ~ optText(expr)(" " ~ _) }
case Try(expr, cases, finalizer) =>
@@ -519,22 +536,40 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case _ =>
tree.fallbackToText(this)
}
+
var txt = toTextCore(tree)
+
+ def suppressTypes =
+ tree.isType || tree.isDef || // don't print types of types or defs
+ homogenizedView && ctx.mode.is(Mode.Pattern)
+ // When comparing pickled info, disregard types of patterns.
+ // The reason is that GADT matching can rewrite types of pattern trees
+ // without changing the trees themselves. (see Typer.typedCase.indexPatterns.transform).
+ // But then pickling and unpickling the original trees will yield trees
+ // with the original types before they are rewritten, which causes a discrepancy.
+
+ def suppressPositions = tree match {
+ case _: WithoutTypeOrPos[_] | _: TypeTree => true // TypeTrees never have an interesting position
+ case _ => false
+ }
+
if (ctx.settings.printtypes.value && tree.hasType) {
- val tp = tree.typeOpt match {
+ // add type to term nodes; replace type nodes with their types unless -Yprintpos is also set.
+ def tp = tree.typeOpt match {
case tp: TermRef if tree.isInstanceOf[RefTree] && !tp.denot.isOverloaded => tp.underlying
case tp => tp
}
- if (tree.isType) txt = toText(tp)
- else if (!tree.isDef) txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close
+ if (!suppressTypes)
+ txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close
+ else if (tree.isType && !homogenizedView)
+ txt = toText(tp)
}
- else if (homogenizedView && tree.isType)
- txt = toText(tree.typeOpt)
- if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]]) {
+ if (printPos && !suppressPositions) {
+ // add positions
val pos =
if (homogenizedView && !tree.isInstanceOf[MemberDef]) tree.pos.toSynthetic
else tree.pos
- val clsStr = "" // DEBUG: if (tree.isType) tree.getClass.toString else ""
+ val clsStr = ""//if (tree.isType) tree.getClass.toString else ""
txt = (txt ~ "@" ~ pos.toString ~ clsStr).close
}
tree match {
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index fc70ac4f2..2fb85b6c0 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -46,10 +46,10 @@ class Pickler extends Phase {
val treePkl = pickler.treePkl
treePkl.pickle(tree :: Nil)
treePkl.compactify()
- pickler.addrsOfTree = treePkl.buf.addrsOfTree
+ pickler.addrOfTree = treePkl.buf.addrOfTree
pickler.addrOfSym = treePkl.addrOfSym
if (tree.pos.exists)
- new PositionPickler(pickler, treePkl.buf.addrsOfTree).picklePositions(tree :: Nil)
+ new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
def rawBytes = // not needed right now, but useful to print raw format.
pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 7e51635e5..1ed47d92e 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -175,7 +175,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
Checking.checkRealizable(qual.tpe, qual.pos.focus)
super.transform(tree)
}
- else
+ else
transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil)
case tree: Super =>
if (ctx.owner.enclosingMethod.isInlineMethod)
diff --git a/tests/pickling/annot.scala b/tests/pickling/annot.scala
new file mode 100644
index 000000000..d20a6cbf4
--- /dev/null
+++ b/tests/pickling/annot.scala
@@ -0,0 +1,12 @@
+trait Type
+class RefinedType extends Type
+
+
+object TestAnnot {
+ def toText(tp: Type) = tp match {
+ case tp: RefinedType =>
+ val parent :: (refined: List[RefinedType @unchecked]) = ???
+ ???
+ }
+ val xs: List[RefinedType @unchecked] = ???
+}
diff --git a/tests/pickling/pickleTypes.scala b/tests/pickling/pickleTypes.scala
new file mode 100644
index 000000000..ef322816a
--- /dev/null
+++ b/tests/pickling/pickleTypes.scala
@@ -0,0 +1,13 @@
+object pickleTypes {
+
+ abstract class C { type T; val x: T; def f: T; def g(y: T): T; def h[U](z: U, y: T): U }
+
+ val x1: Int = ???
+ val x2: List[List[Int]] = ???
+ val x3: C { type T <: C } = ???
+ val x4: C { type T = Int; val x: Int } = ???
+ val x5: C { type T = String; def f: String; def g(y: String): String } = ???
+ val x6: C { type T = String; def f: String; def g(y: String): String; def h[U](z: U, y: T): U } = ???
+
+
+}
diff --git a/tests/pickling/simple.scala b/tests/pickling/simple.scala
new file mode 100644
index 000000000..243b41117
--- /dev/null
+++ b/tests/pickling/simple.scala
@@ -0,0 +1,6 @@
+object Simple {}
+/*class Simple {
+ val x = 3
+ val y: String = ""
+}*/
+