diff options
author | Dmitry Petrashko <dark@d-d.me> | 2015-04-09 09:53:08 +0200 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2015-04-09 09:53:08 +0200 |
commit | 957923ec75c71ac9f7efe67823781438177aaa59 (patch) | |
tree | bb30156964be6feb7dc0f63a214a9c7b42f50596 /src | |
parent | e1e0e9abb6c2b6285d598e260cc1d1c4ac2d3c2a (diff) | |
parent | 9a7a7b889c9ded58ceaefb90f6ee208c9d2ab534 (diff) | |
download | dotty-957923ec75c71ac9f7efe67823781438177aaa59.tar.gz dotty-957923ec75c71ac9f7efe67823781438177aaa59.tar.bz2 dotty-957923ec75c71ac9f7efe67823781438177aaa59.zip |
Merge pull request #465 from dotty-staging/fix/pickling
Fix/pickling
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/config/JavaPlatform.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 25 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/NameOps.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 59 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 21 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/NameBuffer.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/PickleFormat.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TastyName.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TastyPrinter.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TastyUnpickler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TreePickler.scala | 64 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala | 165 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/PlainPrinter.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 1 |
15 files changed, 218 insertions, 171 deletions
diff --git a/src/dotty/tools/dotc/config/JavaPlatform.scala b/src/dotty/tools/dotc/config/JavaPlatform.scala index 043f41a44..41a9c7113 100644 --- a/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -4,9 +4,8 @@ package config import io.{AbstractFile,ClassPath,JavaClassPath,MergedClassPath,DeltaClassPath} import ClassPath.{ JavaContext, DefaultJavaContext } -import core.Contexts._ -import core.SymDenotations._, core.Symbols._, dotty.tools.dotc.core._ -import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._ +import core._ +import Symbols._, Types._, Contexts._, Denotations._, SymDenotations._, StdNames._, Names._ import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._ class JavaPlatform extends Platform { diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 6ca1bae8f..849e934f0 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -476,12 +476,14 @@ object Denotations { /** The version of this SingleDenotation that was valid in the first phase * of this run. */ - def initial: SingleDenotation = { - var current = nextInRun - while (current.validFor.code > this.myValidFor.code) current = current.nextInRun - current - } - + def initial: SingleDenotation = + if (validFor == Nowhere) this + else { + var current = nextInRun + while (current.validFor.code > this.myValidFor.code) current = current.nextInRun + current + } + def history: List[SingleDenotation] = { val b = new ListBuffer[SingleDenotation] var current = initial @@ -493,6 +495,9 @@ object Denotations { b.toList } + /** Invalidate all caches and fields that depend on base classes and their contents */ + def invalidateInheritedInfo(): Unit = () + /** Move validity period of this denotation to a new run. Throw a StaleSymbol error * if denotation is no longer valid. */ @@ -502,9 +507,10 @@ object Denotations { var d: SingleDenotation = denot do { d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId) + d.invalidateInheritedInfo() d = d.nextInRun } while (d ne denot) - syncWithParents + this case _ => if (coveredInterval.containsPhaseId(ctx.phaseId)) staleSymbolError else NoDenotation @@ -611,16 +617,13 @@ object Denotations { val current = symbol.current // println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}") // printPeriods(current) - if (current.nextInRun ne current) - this.nextInRun = current.nextInRun - else - this.nextInRun = this this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId) if (current.validFor.firstPhaseId == targetId) { // replace current with this denotation var prev = current while (prev.nextInRun ne current) prev = prev.nextInRun prev.nextInRun = this + this.nextInRun = current.nextInRun current.validFor = Nowhere } else { // insert this denotation after current diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 60e429bb3..13ff92a8a 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -147,20 +147,26 @@ object NameOps { /** The superaccessor for method with given name */ def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName - /** The expanded name of `name` relative to this class `base` with given `separator` + /** The expanded name of `name` relative to given class `base`. */ def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated('$')) /** The expanded name of `name` relative to `basename` with given `separator` */ - def expandedName(prefix: Name)(implicit ctx: Context): N = + def expandedName(prefix: Name): N = name.fromName(prefix ++ nme.EXPAND_SEPARATOR ++ name).asInstanceOf[N] def unexpandedName: N = { val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N] } + + def expandedPrefix: N = { + val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) + assert(idx >= 0) + name.take(idx).asInstanceOf[N] + } def shadowedName: N = likeTyped(nme.SHADOWED ++ name) diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 1285d3fdd..e572f129b 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -41,15 +41,19 @@ trait SymDenotations { this: Context => def stillValid(denot: SymDenotation): Boolean = if (denot is ValidForever) true - else try { - val owner = denot.owner.denot - stillValid(owner) && ( - !owner.isClass - || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) - || denot.isSelfSym - ) - } catch { - case ex: StaleSymbol => false + else { + val initial = denot.initial + if (initial ne denot) + ctx.withPhase(initial.validFor.firstPhaseId).stillValid(initial.asSymDenotation) + else try { + val owner = denot.owner.denot + stillValid(owner) && ( + !owner.isClass + || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) + || denot.isSelfSym) + } catch { + case ex: StaleSymbol => false + } } } @@ -70,6 +74,12 @@ object SymDenotations { override def hasUniqueSym: Boolean = exists + /** Debug only + override def validFor_=(p: Period) = { + super.validFor_=(p) + } + */ + // ------ Getting and setting fields ----------------------------- private[this] var myFlags: FlagSet = adaptFlags(initFlags) @@ -171,13 +181,13 @@ object SymDenotations { myInfo = tp } - /** The name, except - * - if this is a module class, strip the module class suffix - * - if this is a companion object with a clash-avoiding name, strip the + /** The name, except + * - if this is a module class, strip the module class suffix + * - if this is a companion object with a clash-avoiding name, strip the * "avoid clash" suffix */ def effectiveName(implicit ctx: Context) = - if (this is ModuleClass) name.stripModuleClassSuffix + if (this is ModuleClass) name.stripModuleClassSuffix else name.stripAvoidClashSuffix /** The privateWithin boundary, NoSymbol if no boundary is given. @@ -195,7 +205,7 @@ object SymDenotations { /** Update the annotations of this denotation */ private[core] final def annotations_=(annots: List[Annotation]): Unit = - myAnnotations = annots + myAnnotations = annots /** Does this denotation have an annotation matching the given class symbol? */ final def hasAnnotation(cls: Symbol)(implicit ctx: Context) = @@ -241,9 +251,9 @@ object SymDenotations { /** The symbols defined in this class or object. * Careful! This does not force the type, so is compilation order dependent. * This method should be used only in the following circumstances: - * - * 1. When accessing type parameters or type parameter accessors (both are entered before - * completion). + * + * 1. When accessing type parameters or type parameter accessors (both are entered before + * completion). * 2. When obtaining the current scope in order to enter, rename or delete something there. * 3. When playing it safe in order not to raise CylicReferences, e.g. for printing things * or taking more efficient shortcuts (e.g. the stillValid test). @@ -292,7 +302,6 @@ object SymDenotations { if (isType) fn.toTypeName else fn.toTermName } - /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ def flatName(separator: Char = '$')(implicit ctx: Context): Name = if (symbol == NoSymbol || owner == NoSymbol || owner.isEffectiveRoot || (owner is PackageClass)) name @@ -457,7 +466,7 @@ object SymDenotations { } /** Is this a user defined "def" method? Excluded are accessors and anonymous functions. */ - final def isSourceMethod(implicit ctx: Context) = + final def isSourceMethod(implicit ctx: Context) = this.is(Method, butNot = AccessorOrLabel) && !isAnonymousFunction /** Is this a setter? */ @@ -649,7 +658,7 @@ object SymDenotations { */ /** The class implementing this module, NoSymbol if not applicable. */ final def moduleClass(implicit ctx: Context): Symbol = { - def notFound = {println(s"missing module class for $name: $myInfo"); NoSymbol} + def notFound = { println(s"missing module class for $name: $myInfo"); NoSymbol } if (this is ModuleVal) myInfo match { case info: TypeRef => info.symbol @@ -1002,7 +1011,7 @@ object SymDenotations { s"$kindString $name" } - def debugString = toString+"#"+symbol.id // !!! DEBUG + def debugString = toString + "#" + symbol.id // !!! DEBUG // ----- copies and transforms ---------------------------------------- @@ -1097,8 +1106,8 @@ object SymDenotations { private var firstRunId: RunId = initRunId - /** If caches influenced by parent classes are still valid, the denotation - * itself, otherwise a freshly initialized copy. + /** invalidate caches influenced by parent classes if one of the parents + * is younger than the denotation itself. */ override def syncWithParents(implicit ctx: Context): SingleDenotation = { def isYounger(tref: TypeRef) = tref.symbol.denot match { @@ -1124,7 +1133,7 @@ object SymDenotations { } /** Invalidate all caches and fields that depend on base classes and their contents */ - private def invalidateInheritedInfo(): Unit = { + override def invalidateInheritedInfo(): Unit = { myBaseClasses = null mySuperClassBits = null myMemberFingerPrint = FingerPrint.unknown @@ -1168,7 +1177,7 @@ object SymDenotations { private[this] var myBaseClasses: List[ClassSymbol] = null private[this] var mySuperClassBits: BitSet = null - /** Invalidate baseTypeRefCache, baseClasses and superClassBits on new run */ + /** Invalidate baseTypeRefCache, baseClasses and superClassBits on new run */ private def checkBasesUpToDate()(implicit ctx: Context) = if (baseTypeRefValid != ctx.runId) { baseTypeRefCache = new java.util.HashMap[CachedType, Type] diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 02526a30b..6c3fef1a9 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -191,6 +191,17 @@ class TypeApplications(val self: Type) extends AnyVal { if (res.isInstantiatedLambda) res.select(tpnme.Apply) else res } } + + /** Simplify a fully instantiated type of the form `LambdaX{... type Apply = T } # Apply` to `T`. + */ + def simplifyApply(implicit ctx: Context): Type = self match { + case self @ TypeRef(prefix, tpnme.Apply) if prefix.isInstantiatedLambda => + prefix.member(tpnme.Apply).info match { + case TypeAlias(alias) => alias + case _ => self + } + case _ => self + } final def appliedTo(arg: Type)(implicit ctx: Context): Type = appliedTo(arg :: Nil) final def appliedTo(arg1: Type, arg2: Type)(implicit ctx: Context): Type = appliedTo(arg1 :: arg2 :: Nil) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ea4101558..31567fee0 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -480,7 +480,7 @@ object Types { case ex: MergeError => throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}") case ex: Throwable => - println(i"findMember exception for $this: ${this.widen} member $name") + println(s"findMember exception for $this member $name") throw ex // DEBUG } finally { recCount -= 1 @@ -1158,7 +1158,7 @@ object Types { private[this] var lastDenotation: Denotation = _ private[this] var lastSymbol: Symbol = _ private[this] var checkedPeriod = Nowhere - + // Invariants: // (1) checkedPeriod != Nowhere => lastDenotation != null // (2) lastDenotation != null => lastSymbol != null @@ -1238,8 +1238,7 @@ object Types { // phase but a defined denotation earlier (e.g. a TypeRef to an abstract type // is undefined after erasure.) We need to be able to do time travel back and // forth also in these cases. - lastDenotation = d - lastSymbol = d.symbol + setDenot(d) checkedPeriod = ctx.period } d @@ -1256,9 +1255,14 @@ object Types { private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = assert( (lastSymbol eq sym) || - (lastSymbol eq null) || - (lastSymbol.defRunId != sym.defRunId) || - (lastSymbol.defRunId == NoRunId) || + (lastSymbol eq null) || { + val lastDefRunId = lastDenotation match { + case d: SymDenotation => d.validFor.runId + case _ => lastSymbol.defRunId + } + (lastDefRunId != sym.defRunId) || + (lastDefRunId == NoRunId) + } || (lastSymbol.infoOrCompleter == ErrorType || defn.overriddenBySynthetic.contains(lastSymbol) // for overriddenBySynthetic symbols a TermRef such as SomeCaseClass.this.hashCode @@ -1280,6 +1284,9 @@ object Types { if (Config.checkNoDoubleBindings) if (ctx.settings.YnoDoubleBindings.value) checkSymAssign(denot.symbol) + + // additional checks that intercept `denot` can be added here + lastDenotation = denot lastSymbol = denot.symbol } diff --git a/src/dotty/tools/dotc/core/pickling/NameBuffer.scala b/src/dotty/tools/dotc/core/pickling/NameBuffer.scala index be557f0b1..a60767fe6 100644 --- a/src/dotty/tools/dotc/core/pickling/NameBuffer.scala +++ b/src/dotty/tools/dotc/core/pickling/NameBuffer.scala @@ -65,9 +65,9 @@ class NameBuffer extends TastyBuffer(100000) { case Signed(original, params, result) => writeByte(SIGNED) withLength { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) } - case Expanded(original) => + case Expanded(prefix, original) => writeByte(EXPANDED) - withLength { writeNameRef(original) } + withLength { writeNameRef(prefix); writeNameRef(original) } case ModuleClass(module) => writeByte(OBJECTCLASS) withLength { writeNameRef(module) } diff --git a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala index d37a3673d..872265e2d 100644 --- a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala +++ b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala @@ -269,7 +269,7 @@ object PickleFormat { final val DOUBLEconst = 76 final val STRINGconst = 77 final val IMPORTED = 78 - + final val THIS = 96 final val CLASSconst = 97 final val ENUMconst = 98 diff --git a/src/dotty/tools/dotc/core/pickling/TastyName.scala b/src/dotty/tools/dotc/core/pickling/TastyName.scala index 8508d7ffa..e8f30a234 100644 --- a/src/dotty/tools/dotc/core/pickling/TastyName.scala +++ b/src/dotty/tools/dotc/core/pickling/TastyName.scala @@ -15,7 +15,7 @@ object TastyName { case class Simple(name: TermName) extends TastyName case class Qualified(qualified: NameRef, selector: NameRef) extends TastyName case class Signed(original: NameRef, params: List[NameRef], result: NameRef) extends TastyName - case class Expanded(original: NameRef) extends TastyName + case class Expanded(prefix: NameRef, original: NameRef) extends TastyName case class ModuleClass(module: NameRef) extends TastyName case class SuperAccessor(accessed: NameRef) extends TastyName case class DefaultGetter(method: NameRef, num: Int) extends TastyName diff --git a/src/dotty/tools/dotc/core/pickling/TastyPrinter.scala b/src/dotty/tools/dotc/core/pickling/TastyPrinter.scala index 91cc168ea..a3d30b9b2 100644 --- a/src/dotty/tools/dotc/core/pickling/TastyPrinter.scala +++ b/src/dotty/tools/dotc/core/pickling/TastyPrinter.scala @@ -5,6 +5,7 @@ package pickling import Contexts._, Decorators._ import printing.Texts._ import TastyName._ +import StdNames._ import TastyUnpickler._ import TastyBuffer.Addr import util.Positions.{Position, offsetToInt} @@ -20,7 +21,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { case Qualified(qual, name) => nameRefToString(qual) + "." + nameRefToString(name) case Signed(original, params, result) => i"${nameRefToString(original)}@${params.map(nameRefToString)}%,%:${nameRefToString(result)}" - case Expanded(original) => nameRefToString(original) + "/EXPANDED" + case Expanded(prefix, original) => s"$prefix${nme.EXPAND_SEPARATOR}$original" case ModuleClass(original) => nameRefToString(original) + "/MODULECLASS" case SuperAccessor(accessed) => nameRefToString(accessed) + "/SUPERACCESSOR" case DefaultGetter(meth, num) => nameRefToString(meth) + "/DEFAULTGETTER" + num diff --git a/src/dotty/tools/dotc/core/pickling/TastyUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TastyUnpickler.scala index e5eabaf36..b5e978afa 100644 --- a/src/dotty/tools/dotc/core/pickling/TastyUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TastyUnpickler.scala @@ -51,7 +51,7 @@ class TastyUnpickler(reader: TastyReader) { val params = until(end)(readNameRef()) Signed(original, params, result) case EXPANDED => - Expanded(readNameRef()) + Expanded(readNameRef(), readNameRef()) case OBJECTCLASS => ModuleClass(readNameRef()) case SUPERACCESSOR => diff --git a/src/dotty/tools/dotc/core/pickling/TreePickler.scala b/src/dotty/tools/dotc/core/pickling/TreePickler.scala index c5e07ffa9..85addc563 100644 --- a/src/dotty/tools/dotc/core/pickling/TreePickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreePickler.scala @@ -8,6 +8,7 @@ import PickleFormat._ import core._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable +import NameOps._ import TastyBuffer._ class TreePickler(pickler: TastyPickler) { @@ -31,20 +32,6 @@ class TreePickler(pickler: TastyPickler) { symRefs.get(sym) } - private var makeSymbolicRefsTo: Symbol = NoSymbol - - /** All references to members of class `sym` are pickled - * as symbolic references. Used to pickle the self info of a class. - * Without this precaution we get an infinite cycle when unpickling pos/extmethods.scala - * The problem arises when a self type of a trait is a type parameter of the same trait. - */ - private def withSymbolicRefsTo[T](sym: Symbol)(op: => T): T = { - val saved = makeSymbolicRefsTo - makeSymbolicRefsTo = sym - try op - finally makeSymbolicRefsTo = saved - } - def preRegister(tree: Tree)(implicit ctx: Context): Unit = tree match { case tree: MemberDef => if (!symRefs.contains(tree.symbol)) symRefs(tree.symbol) = NoAddr @@ -61,13 +48,19 @@ class TreePickler(pickler: TastyPickler) { } } - private def pickleName(name: Name) = writeNat(nameIndex(name).index) - private def pickleName(name: TastyName) = writeNat(nameIndex(name).index) + private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) + private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index) private def pickleNameAndSig(name: Name, sig: Signature) = { val Signature(params, result) = sig pickleName(TastyName.Signed(nameIndex(name), params.map(fullNameIndex), fullNameIndex(result))) } - + + private def pickleName(sym: Symbol)(implicit ctx: Context): Unit = + if (sym is Flags.ExpandedName) + pickleName(TastyName.Expanded( + nameIndex(sym.name.expandedPrefix), nameIndex(sym.name.unexpandedName))) + else pickleName(sym.name) + private def pickleSymRef(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { case Some(label) => if (label != NoAddr) writeRef(label) else pickleForwardSymRef(sym) @@ -81,6 +74,11 @@ class TreePickler(pickler: TastyPickler) { assert(!sym.is(Flags.Package), sym) forwardSymRefs(sym) = ref :: forwardSymRefs.getOrElse(sym, Nil) } + + private def isLocallyDefined(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { + case Some(label) => assert(sym.exists); label != NoAddr + case None => false + } def pickle(trees: List[Tree])(implicit ctx: Context) = { @@ -155,7 +153,8 @@ class TreePickler(pickler: TastyPickler) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) pickleName(qualifiedName(sym)) } - else if (tpe.prefix == NoPrefix) { + else { + assert(tpe.prefix == NoPrefix) def pickleRef() = { writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) pickleSymRef(sym) @@ -171,10 +170,6 @@ class TreePickler(pickler: TastyPickler) { } else pickleRef() } - else { - writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) - pickleSymRef(sym); pickleType(tpe.prefix) - } case tpe: TermRefWithSignature => writeByte(TERMREF) pickleNameAndSig(tpe.name, tpe.signature); pickleType(tpe.prefix) @@ -183,12 +178,13 @@ class TreePickler(pickler: TastyPickler) { // instantiated lambdas are pickled as APPLIEDTYPE; #Apply will // be reconstituted when unpickling. pickleType(tpe.prefix) - else tpe.prefix match { - case prefix: ThisType if prefix.cls == makeSymbolicRefsTo => - pickleType(NamedType.withFixedSym(tpe.prefix, tpe.symbol)) - case _ => - writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(tpe.name); pickleType(tpe.prefix) + else 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 => writeByte(THIS) @@ -425,12 +421,10 @@ class TreePickler(pickler: TastyPickler) { if ((selfInfo ne NoType) || !tree.self.isEmpty) { writeByte(SELFDEF) pickleName(tree.self.name) - withSymbolicRefsTo(tree.symbol.owner) { - pickleType { - cinfo.selfInfo match { - case sym: Symbol => sym.info - case tp: Type => tp - } + pickleType { + cinfo.selfInfo match { + case sym: Symbol => sym.info + case tp: Type => tp } } } @@ -464,7 +458,7 @@ class TreePickler(pickler: TastyPickler) { registerDef(sym) writeByte(tag) withLength { - pickleName(sym.name) + pickleName(sym) pickleParams tpt match { case tpt: TypeTree => pickleTpt(tpt) diff --git a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala index 7d80065cf..c46ff8d6f 100644 --- a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala @@ -70,7 +70,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case Qualified(qual, name) => toTermName(qual) ++ "." ++ toTermName(name) case Signed(original, params, result) => toTermName(original) case Shadowed(original) => toTermName(original).shadowedName - case Expanded(original) => ??? + case Expanded(prefix, original) => toTermName(original).expandedName(toTermName(prefix)) case ModuleClass(original) => toTermName(original).moduleClassName.toTermName case SuperAccessor(accessed) => ??? case DefaultGetter(meth, num) => ??? @@ -102,6 +102,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { def skipParams(): Unit = while (nextByte == PARAMS || nextByte == TYPEPARAM) skipTree() + /** The next tag, following through SHARED tags */ + def nextUnsharedTag: Int = { + val tag = nextByte + if (tag == SHARED) { + val lookAhead = fork + lookAhead.reader.readByte() + forkAt(lookAhead.reader.readAddr()).nextUnsharedTag + } + else tag + } + def readName(): TermName = toTermName(readNameRef()) def readNameSplitSig()(implicit ctx: Context): Any /* TermName | (TermName, Signature) */ = @@ -172,17 +183,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case REFINEDtype => val parent = readType() var name: Name = readName() - if (nextByte == SHARED) { - val refinedInfo = readType() - if (refinedInfo.isInstanceOf[TypeBounds]) name = name.toTypeName - RefinedType(parent, name, refinedInfo) - } - else { - if (nextByte == TYPEBOUNDS || nextByte == TYPEALIAS) name = name.toTypeName - RefinedType(parent, name, rt => registeringType(rt, readType())) - // Note that the lambda is not equivalent to a wildcard closure! - // Eta expansion of the latter puts readType() out of the expression. - } + val ttag = nextUnsharedTag + if (ttag == TYPEBOUNDS || ttag == TYPEALIAS) name = name.toTypeName + RefinedType(parent, name, rt => registeringType(rt, readType())) + // Note that the lambda "rt => ..." is not equivalent to a wildcard closure! + // Eta expansion of the latter puts readType() out of the expression. case APPLIEDtype => readType().appliedTo(until(end)(readType())) case TYPEBOUNDS => @@ -235,26 +240,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case TYPEREFdirect | TERMREFdirect => NamedType.withFixedSym(NoPrefix, readSymRef()) case TYPEREFsymbol | TERMREFsymbol => - val sym = readSymRef() - val prefix = readType() - val res = NamedType.withFixedSym(prefix, sym) - if (prefix.isInstanceOf[ThisType]) res.withDenot(sym.denot) else res - // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala - // the problem arises when a self type of a trait is a type parameter of the same trait. + readSymNameRef() case TYPEREFpkg => - val name = readName() - val pkg = - if (name == nme.ROOT) defn.RootClass - else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageClass - else ctx.requiredPackage(name).moduleClass - pkg.typeRef + readPackageRef().moduleClass.typeRef case TERMREFpkg => - val name = readName() - val pkg = - if (name == nme.ROOT) defn.RootPackage - else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageVal - else ctx.requiredPackage(name) - pkg.termRef + readPackageRef().termRef case TYPEREF => val name = readName().toTypeName TypeRef(readType(), name) @@ -301,6 +291,25 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { if (tag < firstLengthTreeTag) readSimpleType() else readLengthType() } + private def readSymNameRef()(implicit ctx: Context): Type = { + val sym = readSymRef() + val prefix = readType() + val res = NamedType.withSymAndName(prefix, sym, sym.name) + prefix match { + case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot) + // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala + // the problem arises when a self type of a trait is a type parameter of the same trait. + case _ => res + } + } + + private def readPackageRef()(implicit ctx: Context): TermSymbol = { + val name = readName() + if (name == nme.ROOT) defn.RootPackage + else if (name == nme.EMPTY_PACKAGE) defn.EmptyPackageVal + else ctx.requiredPackage(name) + } + def readTypeRef(): Type = typeAtAddr(readAddr()) @@ -325,16 +334,16 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbstractType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = { val lacksDefinition = - rhsIsEmpty && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || + rhsIsEmpty && + name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || isAbstractType var flags = givenFlags if (lacksDefinition) flags |= Deferred if (tag == DEFDEF) flags |= Method if (givenFlags is Module) flags = flags | (if (tag == VALDEF) ModuleCreationFlags else ModuleClassCreationFlags) - if (ctx.mode.is(Mode.InSuperCall) && !flags.is(ParamOrAccessor)) flags |= InSuperCall if (ctx.owner.isClass) { - if (tag == TYPEPARAM) flags |= Param | ExpandedName // TODO check name to determine ExpandedName + if (tag == TYPEPARAM) flags |= Param else if (tag == PARAM) flags |= ParamAccessor } else if (isParamTag(tag)) flags |= Param @@ -348,52 +357,56 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { val start = currentAddr val tag = readByte() val end = readEnd() - val name = if (tag == TYPEDEF || tag == TYPEPARAM) readName().toTypeName else readName() + val rawName = tastyName(readNameRef()) + var name: Name = toTermName(rawName) + if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName skipParams() - val isAbstractType = nextByte == TYPEBOUNDS - val isClass = nextByte == TEMPLATE + val ttag = nextUnsharedTag + val isAbstractType = ttag == TYPEBOUNDS + val isClass = ttag == TEMPLATE val templateStart = currentAddr skipTree() // tpt val rhsIsEmpty = noRhs(end) if (!rhsIsEmpty) skipTree() val (givenFlags, annots, privateWithin) = readModifiers(end) + val expandedFlag = if (rawName.isInstanceOf[TastyName.Expanded]) ExpandedName else EmptyFlags pickling.println(i"creating symbol $name at $start with flags $givenFlags") - val flags = normalizeFlags(tag, givenFlags, name, isAbstractType, rhsIsEmpty) - val nameMatches = (_: Denotation).symbol.name == name - val prevDenot: SymDenotation = - if (ctx.owner.is(Package)) ctx.effectiveScope.lookup(name) - else NoDenotation // TODO check for double reads - var completer: LazyType = - if (prevDenot.exists) new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter - else new Completer(subReader(start, end)) - if (flags is Module) completer = ctx.adjustModuleCompleter(completer, name) + val flags = normalizeFlags(tag, givenFlags | expandedFlag, name, isAbstractType, rhsIsEmpty) + def adjustIfModule(completer: LazyType) = + if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer val sym = - if (roots contains prevDenot) { - pickling.println(i"overwriting ${prevDenot.symbol} # ${prevDenot.hashCode}") - prevDenot.info = completer - prevDenot.flags = flags &~ Touched // allow one more completion - prevDenot.privateWithin = privateWithin - prevDenot.symbol - } else if (isClass) - ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index) - else { - val sym = symAtAddr.get(start) match { - case Some(preExisting) => - assert(stubs contains preExisting) - stubs -= preExisting - preExisting - case none => - ctx.newNakedSymbol(start.index) - } - val denot = ctx.SymDenotation(symbol = sym, owner = ctx.owner, name, flags, completer, privateWithin) - sym.denot = denot - sym + roots.find(root => (root.owner eq ctx.owner) && root.name == name) match { + case Some(rootd) => + pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}") + rootd.info = adjustIfModule( + new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter) + rootd.flags = flags &~ Touched // allow one more completion + rootd.privateWithin = privateWithin + rootd.symbol + case _ => + val completer = adjustIfModule(new Completer(subReader(start, end))) + if (isClass) + ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, + privateWithin, coord = start.index) + else { + val sym = symAtAddr.get(start) match { + case Some(preExisting) => + assert(stubs contains preExisting) + stubs -= preExisting + preExisting + case none => + ctx.newNakedSymbol(start.index) + } + val denot = ctx.SymDenotation(symbol = sym, owner = ctx.owner, name, flags, completer, privateWithin) + sym.denot = denot + sym + } } // TODO set position sym.annotations = annots ctx.enter(sym) symAtAddr(start) = sym if (isClass) { - completer.withDecls(newScope) + sym.completer.withDecls(newScope) forkAt(templateStart).indexTemplateParams()(localContext(sym)) } tag != VALDEF || rhsIsEmpty @@ -567,17 +580,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { sym.info = readType() ValDef(sym.asTerm, readRhs(localCtx)) case TYPEDEF | TYPEPARAM => - if (sym.isClass) { - val cls = sym.asClass - def setClsInfo(parents: List[TypeRef], selfType: Type) = - cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType) - setClsInfo(Nil, NoType) - val impl = readTemplate(localCtx) - setClsInfo( - ctx.normalizeToClassRefs(impl.parents.map(_.tpe), cls, cls.unforcedDecls), - if (impl.self.isEmpty) NoType else impl.self.tpt.tpe) - ta.assignType(untpd.TypeDef(sym.name.asTypeName, impl), sym) - } + if (sym.isClass) + ta.assignType(untpd.TypeDef(sym.name.asTypeName, readTemplate(localCtx)), sym) else { sym.info = readType() TypeDef(sym.asType) @@ -606,6 +610,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { private def readTemplate(implicit ctx: Context): Template = { val start = currentAddr val cls = ctx.owner.asClass + def setClsInfo(parents: List[TypeRef], selfType: Type) = + cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType) + setClsInfo(Nil, NoType) val localDummy = ctx.newLocalDummy(cls) assert(readByte() == TEMPLATE) val end = readEnd() @@ -617,12 +624,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case _ => readTpt() } } - val self = + val parentRefs = ctx.normalizeToClassRefs(parents.map(_.tpe), cls, cls.unforcedDecls) + val self = if (nextByte == SELFDEF) { readByte() untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType) } else EmptyValDef + setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe) val noInits = fork.indexStats(end) if (noInits) cls.setFlag(NoInits) val constr = readIndexedDef().asInstanceOf[DefDef] diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 0fd862afb..ce33132ab 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -37,10 +37,17 @@ class PlainPrinter(_ctx: Context) extends Printer { /** If true, tweak output so it is the same before and after pickling */ protected def homogenizedView: Boolean = ctx.settings.YtestPickler.value - def homogenize(tp: Type): Type = tp match { - case tp: TypeVar if homogenizedView && tp.isInstantiated => homogenize(tp.instanceOpt) - case _ => tp - } + def homogenize(tp: Type): Type = + if (homogenizedView) + tp match { + case tp: TypeVar if tp.isInstantiated => homogenize(tp.instanceOpt) + case AndType(tp1, tp2) => homogenize(tp1) & homogenize(tp2) + case OrType(tp1, tp2) => homogenize(tp1) | homogenize(tp2) + case _ => + val tp1 = tp.simplifyApply + if (tp1 eq tp) tp else homogenize(tp1) + } + else tp /** Render elements alternating with `sep` string */ protected def toText(elems: Traversable[Showable], sep: String) = diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index e238f21ef..626a75139 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -65,6 +65,7 @@ class Pickler extends Phase { unpickler.enter(roots = Set()) unpickler } + pickling.println("************* entered toplevel ***********") for ((unpickler, unit) <- unpicklers zip units) { val unpickled = unpickler.body(readPositions = false) testSame(i"$unpickled%\n%", beforePickling(unit), unit) |