aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/unpickleScala2
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/unpickleScala2
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/unpickleScala2')
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala299
-rw-r--r--compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala1260
2 files changed, 1559 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala
new file mode 100644
index 000000000..17fef3852
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala
@@ -0,0 +1,299 @@
+package dotty.tools
+package dotc
+package core
+package unpickleScala2
+
+import Flags._
+
+/** Variable length byte arrays, with methods for basic pickling and unpickling.
+ *
+ * @param data The initial buffer
+ * @param from The first index where defined data are found
+ * @param to The first index where new data can be written
+ */
+class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
+
+ var bytes = data
+ var readIndex = from
+ var writeIndex = to
+
+ /** Double bytes array */
+ private def dble(): Unit = {
+ val bytes1 = new Array[Byte](bytes.length * 2)
+ Array.copy(bytes, 0, bytes1, 0, writeIndex)
+ bytes = bytes1
+ }
+
+ def ensureCapacity(capacity: Int) =
+ while (bytes.length < writeIndex + capacity) dble()
+
+ // -- Basic output routines --------------------------------------------
+
+ /** Write a byte of data */
+ def writeByte(b: Int): Unit = {
+ if (writeIndex == bytes.length) dble()
+ bytes(writeIndex) = b.toByte
+ writeIndex += 1
+ }
+
+ /** Write a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.
+ */
+ def writeNat(x: Int): Unit =
+ writeLongNat(x.toLong & 0x00000000FFFFFFFFL)
+
+ /**
+ * Like writeNat, but for longs. This is not the same as
+ * writeLong, which writes in base 256. Note that the
+ * binary representation of LongNat is identical to Nat
+ * if the long value is in the range Int.MIN_VALUE to
+ * Int.MAX_VALUE.
+ */
+ def writeLongNat(x: Long): Unit = {
+ def writeNatPrefix(x: Long): Unit = {
+ val y = x >>> 7
+ if (y != 0L) writeNatPrefix(y)
+ writeByte(((x & 0x7f) | 0x80).toInt)
+ }
+ val y = x >>> 7
+ if (y != 0L) writeNatPrefix(y)
+ writeByte((x & 0x7f).toInt)
+ }
+
+ /** Write a natural number <code>x</code> at position <code>pos</code>.
+ * If number is more than one byte, shift rest of array to make space.
+ *
+ * @param pos ...
+ * @param x ...
+ */
+ def patchNat(pos: Int, x: Int): Unit = {
+ def patchNatPrefix(x: Int): Unit = {
+ writeByte(0)
+ Array.copy(bytes, pos, bytes, pos + 1, writeIndex - (pos + 1))
+ bytes(pos) = ((x & 0x7f) | 0x80).toByte
+ val y = x >>> 7
+ if (y != 0) patchNatPrefix(y)
+ }
+ bytes(pos) = (x & 0x7f).toByte
+ val y = x >>> 7
+ if (y != 0) patchNatPrefix(y)
+ }
+
+ /** Write a long number <code>x</code> in signed big endian format, base 256.
+ *
+ * @param x The long number to be written.
+ */
+ def writeLong(x: Long): Unit = {
+ val y = x >> 8
+ val z = x & 0xff
+ if (-y != (z >> 7)) writeLong(y)
+ writeByte(z.toInt)
+ }
+
+ // -- Basic input routines --------------------------------------------
+
+ /** Peek at the current byte without moving the read index */
+ def peekByte(): Int = bytes(readIndex)
+
+ /** Read a byte */
+ def readByte(): Int = {
+ val x = bytes(readIndex); readIndex += 1; x
+ }
+
+ /** Read a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.*/
+ def readNat(): Int = readLongNat().toInt
+
+ def readLongNat(): Long = {
+ var b = 0L
+ var x = 0L
+ do {
+ b = readByte()
+ x = (x << 7) + (b & 0x7f)
+ } while ((b & 0x80) != 0L)
+ x
+ }
+
+ /** Read a long number in signed big endian format, base 256. */
+ def readLong(len: Int): Long = {
+ var x = 0L
+ var i = 0
+ while (i < len) {
+ x = (x << 8) + (readByte() & 0xff)
+ i += 1
+ }
+ val leading = 64 - (len << 3)
+ x << leading >> leading
+ }
+
+ /** Returns the buffer as a sequence of (Int, Array[Byte]) representing
+ * (tag, data) of the individual entries. Saves and restores buffer state.
+ */
+
+ def toIndexedSeq: IndexedSeq[(Int, Array[Byte])] = {
+ val saved = readIndex
+ readIndex = 0
+ readNat() ; readNat() // discarding version
+ val result = new Array[(Int, Array[Byte])](readNat())
+
+ result.indices foreach { index =>
+ val tag = readNat()
+ val len = readNat()
+ val bytes = data.slice(readIndex, len + readIndex)
+ readIndex += len
+
+ result(index) = tag -> bytes
+ }
+
+ readIndex = saved
+ result.toIndexedSeq
+ }
+
+ /** Perform operation <code>op</code> until the condition
+ * <code>readIndex == end</code> is satisfied.
+ * Concatenate results into a list.
+ *
+ * @param end ...
+ * @param op ...
+ * @return ...
+ */
+ def until[T](end: Int, op: () => T): List[T] =
+ if (readIndex == end) List() else op() :: until(end, op)
+
+ /** Perform operation <code>op</code> the number of
+ * times specified. Concatenate the results into a list.
+ */
+ def times[T](n: Int, op: ()=>T): List[T] =
+ if (n == 0) List() else op() :: times(n-1, op)
+
+ /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry}
+ * Entry = type_Nat length_Nat [actual entries]
+ *
+ * Assumes that the ..Version_Nat are already consumed.
+ *
+ * @return an array mapping entry numbers to locations in
+ * the byte array where the entries start.
+ */
+ def createIndex: Array[Int] = {
+ val index = new Array[Int](readNat()) // nbEntries_Nat
+ for (i <- 0 until index.length) {
+ index(i) = readIndex
+ readByte() // skip type_Nat
+ readIndex = readNat() + readIndex // read length_Nat, jump to next entry
+ }
+ index
+ }
+}
+
+object PickleBuffer {
+
+ private final val ScalaFlagEnd = 48
+ private final val ChunkBits = 8
+ private final val ChunkSize = 1 << ChunkBits
+ private type FlagMap = Array[Array[Long]]
+
+ private val (scalaTermFlagMap, scalaTypeFlagMap) = {
+ import scala.reflect.internal.Flags._
+
+ // The following vals are copy-pasted from reflect.internal.Flags.
+ // They are unfortunately private there, so we cannot get at them directly.
+ // Using the public method pickledToRawFlags instead looks unattractive
+ // because of performance.
+ val IMPLICIT_PKL = (1 << 0)
+ val FINAL_PKL = (1 << 1)
+ val PRIVATE_PKL = (1 << 2)
+ val PROTECTED_PKL = (1 << 3)
+ val SEALED_PKL = (1 << 4)
+ val OVERRIDE_PKL = (1 << 5)
+ val CASE_PKL = (1 << 6)
+ val ABSTRACT_PKL = (1 << 7)
+ val DEFERRED_PKL = (1 << 8)
+ val METHOD_PKL = (1 << 9)
+ val MODULE_PKL = (1 << 10)
+ val INTERFACE_PKL = (1 << 11)
+
+ val corr = Map(
+ PROTECTED_PKL -> Protected,
+ OVERRIDE_PKL -> Override,
+ PRIVATE_PKL -> Private,
+ ABSTRACT_PKL -> Abstract,
+ DEFERRED_PKL -> Deferred,
+ FINAL_PKL -> Final,
+ METHOD_PKL -> Method,
+ INTERFACE_PKL -> NoInitsInterface,
+ MODULE_PKL -> (Module | Lazy, Module),
+ IMPLICIT_PKL -> Implicit,
+ SEALED_PKL -> Sealed,
+ CASE_PKL -> Case,
+ MUTABLE -> Mutable,
+ PARAM -> Param,
+ PACKAGE -> Package,
+ MACRO -> Macro,
+ BYNAMEPARAM -> (Method, Covariant),
+ LABEL -> (Label, Contravariant),
+ ABSOVERRIDE -> AbsOverride,
+ LOCAL -> Local,
+ JAVA -> JavaDefined,
+ SYNTHETIC -> Synthetic,
+ STABLE -> Stable,
+ STATIC -> JavaStatic,
+ CASEACCESSOR -> CaseAccessor,
+ DEFAULTPARAM -> (DefaultParameterized, Trait),
+ BRIDGE -> Bridge,
+ ACCESSOR -> Accessor,
+ SUPERACCESSOR -> SuperAccessor,
+ PARAMACCESSOR -> ParamAccessor,
+ MODULEVAR -> Scala2ModuleVar,
+ LAZY -> Lazy,
+ MIXEDIN -> (MixedIn, Scala2Existential),
+ EXPANDEDNAME -> ExpandedName,
+ IMPLCLASS -> (Scala2PreSuper, ImplClass),
+ SPECIALIZED -> Specialized,
+ VBRIDGE -> VBridge,
+ VARARGS -> JavaVarargs,
+ ENUM -> Enum)
+
+ // generate initial maps from Scala flags to Dotty flags
+ val termMap, typeMap = new Array[Long](64)
+ for (idx <- 0 until ScalaFlagEnd)
+ corr get (1L << idx) match {
+ case Some((termFlag: FlagSet, typeFlag: FlagSet)) =>
+ termMap(idx) |= termFlag.bits
+ typeMap(idx) |= typeFlag.bits
+ case Some(commonFlag: FlagSet) =>
+ termMap(idx) |= commonFlag.toTermFlags.bits
+ typeMap(idx) |= commonFlag.toTypeFlags.bits
+ case _ =>
+ }
+
+ // Convert map so that it maps chunks of ChunkBits size at once
+ // instead of single bits.
+ def chunkMap(xs: Array[Long]): FlagMap = {
+ val chunked = Array.ofDim[Long](
+ (xs.length + ChunkBits - 1) / ChunkBits, ChunkSize)
+ for (i <- 0 until chunked.length)
+ for (j <- 0 until ChunkSize)
+ for (k <- 0 until ChunkBits)
+ if ((j & (1 << k)) != 0)
+ chunked(i)(j) |= xs(i * ChunkBits + k)
+ chunked
+ }
+
+ (chunkMap(termMap), chunkMap(typeMap))
+ }
+
+ def unpickleScalaFlags(sflags: Long, isType: Boolean): FlagSet = {
+ val map: FlagMap = if (isType) scalaTypeFlagMap else scalaTermFlagMap
+ val shift = ChunkBits
+ val mask = ChunkSize - 1
+ assert(6 * ChunkBits == ScalaFlagEnd)
+ FlagSet(
+ map(0)((sflags >>> (shift * 0)).toInt & mask) |
+ map(1)((sflags >>> (shift * 1)).toInt & mask) |
+ map(2)((sflags >>> (shift * 2)).toInt & mask) |
+ map(3)((sflags >>> (shift * 3)).toInt & mask) |
+ map(4)((sflags >>> (shift * 4)).toInt & mask) |
+ map(5)((sflags >>> (shift * 5)).toInt & mask)
+ )
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
new file mode 100644
index 000000000..b01f6cc6a
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -0,0 +1,1260 @@
+package dotty.tools
+package dotc
+package core
+package unpickleScala2
+
+import java.io.IOException
+import java.lang.Float.intBitsToFloat
+import java.lang.Double.longBitsToDouble
+
+import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
+import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._
+import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto}
+import util.Positions._
+import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._
+import ast.untpd.Modifiers
+import printing.Texts._
+import printing.Printer
+import io.AbstractFile
+import util.common._
+import typer.Checking.checkNonCyclic
+import PickleBuffer._
+import scala.reflect.internal.pickling.PickleFormat._
+import Decorators._
+import TypeApplications._
+import classfile.ClassfileParser
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.ListBuffer
+import scala.annotation.switch
+
+object Scala2Unpickler {
+
+ /** Exception thrown if classfile is corrupted */
+ class BadSignature(msg: String) extends RuntimeException(msg)
+
+ case class TempPolyType(tparams: List[TypeSymbol], tpe: Type) extends UncachedGroundType {
+ override def fallbackToText(printer: Printer): Text =
+ "[" ~ printer.dclsText(tparams, ", ") ~ "]" ~ printer.toText(tpe)
+ }
+
+ /** Temporary type for classinfos, will be decomposed on completion of the class */
+ case class TempClassInfoType(parentTypes: List[Type], decls: Scope, clazz: Symbol) extends UncachedGroundType
+
+ /** Convert temp poly type to poly type and leave other types alone. */
+ def translateTempPoly(tp: Type)(implicit ctx: Context): Type = tp match {
+ case TempPolyType(tparams, restpe) => restpe.LambdaAbstract(tparams)
+ case tp => tp
+ }
+
+ def addConstructorTypeParams(denot: SymDenotation)(implicit ctx: Context) = {
+ assert(denot.isConstructor)
+ denot.info = denot.info.LambdaAbstract(denot.owner.typeParams)
+ }
+
+ /** Convert array parameters denoting a repeated parameter of a Java method
+ * to `RepeatedParamClass` types.
+ */
+ def arrayToRepeated(tp: Type)(implicit ctx: Context): Type = tp match {
+ case tp @ MethodType(paramNames, paramTypes) =>
+ val lastArg = paramTypes.last
+ assert(lastArg isRef defn.ArrayClass)
+ val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass)
+ val elemtp = elemtp0 match {
+ case AndType(t1, t2) if t1.typeSymbol.isAbstractType && (t2 isRef defn.ObjectClass) =>
+ t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.
+ case _ =>
+ elemtp0
+ }
+ tp.derivedMethodType(
+ paramNames,
+ paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp),
+ tp.resultType)
+ case tp: PolyType =>
+ tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType))
+ }
+
+ def ensureConstructor(cls: ClassSymbol, scope: Scope)(implicit ctx: Context) =
+ if (scope.lookup(nme.CONSTRUCTOR) == NoSymbol) {
+ val constr = ctx.newDefaultConstructor(cls)
+ addConstructorTypeParams(constr)
+ cls.enter(constr, scope)
+ }
+
+ def setClassInfo(denot: ClassDenotation, info: Type, selfInfo: Type = NoType)(implicit ctx: Context): Unit = {
+ val cls = denot.classSymbol
+ val (tparams, TempClassInfoType(parents, decls, clazz)) = info match {
+ case TempPolyType(tps, cinfo) => (tps, cinfo)
+ case cinfo => (Nil, cinfo)
+ }
+ val ost =
+ if ((selfInfo eq NoType) && (denot is ModuleClass) && denot.sourceModule.exists)
+ // it seems sometimes the source module does not exist for a module class.
+ // An example is `scala.reflect.internal.Trees.Template$. Without the
+ // `denot.sourceModule.exists` provision i859.scala crashes in the backend.
+ denot.owner.thisType select denot.sourceModule
+ else selfInfo
+ val tempInfo = new TempClassInfo(denot.owner.thisType, denot.classSymbol, decls, ost)
+ denot.info = tempInfo // first rough info to avoid CyclicReferences
+ var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls)
+ if (parentRefs.isEmpty) parentRefs = defn.ObjectType :: Nil
+ for (tparam <- tparams) {
+ val tsym = decls.lookup(tparam.name)
+ if (tsym.exists) tsym.setFlag(TypeParam)
+ else denot.enter(tparam, decls)
+ }
+ if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls)
+
+ val scalacCompanion = denot.classSymbol.scalacLinkedClass
+
+ def registerCompanionPair(module: Symbol, claz: Symbol) = {
+ import transform.SymUtils._
+ module.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, claz)
+ if (claz.isClass) {
+ claz.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, module)
+ }
+ }
+
+ if (denot.flagsUNSAFE is Module) {
+ registerCompanionPair(denot.classSymbol, scalacCompanion)
+ } else {
+ registerCompanionPair(scalacCompanion, denot.classSymbol)
+ }
+
+ tempInfo.finalize(denot, parentRefs) // install final info, except possibly for typeparams ordering
+ denot.ensureTypeParamsInCorrectOrder()
+ }
+}
+
+/** Unpickle symbol table information descending from a class and/or module root
+ * from an array of bytes.
+ * @param bytes bytearray from which we unpickle
+ * @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable
+ * @param moduleroot the top-level module class which is unpickled, or NoSymbol if inapplicable
+ * @param filename filename associated with bytearray, only used for error messages
+ */
+class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(ictx: Context)
+ extends PickleBuffer(bytes, 0, -1) with ClassfileParser.Embedded {
+
+ def showPickled() = {
+ atReadPos(0, () => {
+ println(s"classRoot = ${classRoot.debugString}, moduleClassRoot = ${moduleClassRoot.debugString}")
+ util.ShowPickled.printFile(this)
+ })
+ }
+
+ // print("unpickling "); showPickled() // !!! DEBUG
+
+ import Scala2Unpickler._
+
+ val moduleRoot = moduleClassRoot.sourceModule(ictx).denot(ictx)
+ assert(moduleRoot.isTerm)
+
+ checkVersion(ictx)
+
+ private val loadingMirror = defn(ictx) // was: mirrorThatLoaded(classRoot)
+
+ /** A map from entry numbers to array offsets */
+ private val index = createIndex
+
+ /** A map from entry numbers to symbols, types, or annotations */
+ private val entries = new Array[AnyRef](index.length)
+
+ /** A map from symbols to their associated `decls` scopes */
+ private val symScopes = mutable.AnyRefMap[Symbol, Scope]()
+
+ protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(implicit ctx: Context) = {
+ val ex = new BadSignature(
+ i"""error reading Scala signature of $classRoot from $source:
+ |error occurred at position $readIndex: $msg""")
+ if (ctx.debug || true) original.getOrElse(ex).printStackTrace() // temporarily enable printing of original failure signature to debug failing builds
+ throw ex
+ }
+
+ protected def handleRuntimeException(ex: RuntimeException)(implicit ctx: Context) = ex match {
+ case ex: BadSignature => throw ex
+ case _ => errorBadSignature(s"a runtime exception occurred: $ex", Some(ex))
+ }
+
+ def run()(implicit ctx: Context) =
+ try {
+ var i = 0
+ while (i < index.length) {
+ if (entries(i) == null && isSymbolEntry(i)) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ val sym = readSymbol()
+ entries(i) = sym
+ sym.infoOrCompleter match {
+ case info: ClassUnpickler => info.init()
+ case _ =>
+ }
+ readIndex = savedIndex
+ }
+ i += 1
+ }
+ // read children last, fix for #3951
+ i = 0
+ while (i < index.length) {
+ if (entries(i) == null) {
+ if (isSymbolAnnotationEntry(i)) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ readSymbolAnnotation()
+ readIndex = savedIndex
+ } else if (isChildrenEntry(i)) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ readChildren()
+ readIndex = savedIndex
+ }
+ }
+ i += 1
+ }
+ } catch {
+ case ex: RuntimeException => handleRuntimeException(ex)
+ }
+
+ def source(implicit ctx: Context): AbstractFile = {
+ val f = classRoot.symbol.associatedFile
+ if (f != null) f else moduleClassRoot.symbol.associatedFile
+ }
+
+ private def checkVersion(implicit ctx: Context): Unit = {
+ val major = readNat()
+ val minor = readNat()
+ if (major != MajorVersion || minor > MinorVersion)
+ throw new IOException("Scala signature " + classRoot.fullName.decode +
+ " has wrong version\n expected: " +
+ MajorVersion + "." + MinorVersion +
+ "\n found: " + major + "." + minor +
+ " in " + source)
+ }
+
+ /** The `decls` scope associated with given symbol */
+ protected def symScope(sym: Symbol) = symScopes.getOrElseUpdate(sym, newScope)
+
+ /** Does entry represent an (internal) symbol */
+ protected def isSymbolEntry(i: Int)(implicit ctx: Context): Boolean = {
+ val tag = bytes(index(i)).toInt
+ (firstSymTag <= tag && tag <= lastSymTag &&
+ (tag != CLASSsym || !isRefinementSymbolEntry(i)))
+ }
+
+ /** Does entry represent an (internal or external) symbol */
+ protected def isSymbolRef(i: Int): Boolean = {
+ val tag = bytes(index(i))
+ (firstSymTag <= tag && tag <= lastExtSymTag)
+ }
+
+ /** Does entry represent a name? */
+ protected def isNameEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == TERMname || tag == TYPEname
+ }
+
+ /** Does entry represent a symbol annotation? */
+ protected def isSymbolAnnotationEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == SYMANNOT
+ }
+
+ /** Does the entry represent children of a symbol? */
+ protected def isChildrenEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == CHILDREN
+ }
+
+ /** Does entry represent a refinement symbol?
+ * pre: Entry is a class symbol
+ */
+ protected def isRefinementSymbolEntry(i: Int)(implicit ctx: Context): Boolean = {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ val tag = readByte().toInt
+ assert(tag == CLASSsym)
+
+ readNat(); // read length
+ val result = readNameRef() == tpnme.REFINE_CLASS
+ readIndex = savedIndex
+ result
+ }
+
+ protected def isRefinementClass(sym: Symbol)(implicit ctx: Context): Boolean =
+ sym.name == tpnme.REFINE_CLASS
+
+ protected def isLocal(sym: Symbol)(implicit ctx: Context) = isUnpickleRoot(sym.topLevelClass)
+
+ protected def isUnpickleRoot(sym: Symbol)(implicit ctx: Context) = {
+ val d = sym.denot
+ d == moduleRoot || d == moduleClassRoot || d == classRoot
+ }
+
+ /** If entry at <code>i</code> is undefined, define it by performing
+ * operation <code>op</code> with <code>readIndex at start of i'th
+ * entry. Restore <code>readIndex</code> afterwards.
+ */
+ protected def at[T <: AnyRef](i: Int, op: () => T): T = {
+ var r = entries(i)
+ if (r eq null) {
+ r = atReadPos(index(i), op)
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ }
+ r.asInstanceOf[T]
+ }
+
+ protected def atReadPos[T](start: Int, op: () => T): T = {
+ val savedIndex = readIndex
+ readIndex = start
+ try op()
+ finally readIndex = savedIndex
+ }
+
+ /** Read a name */
+ protected def readName()(implicit ctx: Context): Name = {
+ val tag = readByte()
+ val len = readNat()
+ tag match {
+ case TERMname => termName(bytes, readIndex, len)
+ case TYPEname => typeName(bytes, readIndex, len)
+ case _ => errorBadSignature("bad name tag: " + tag)
+ }
+ }
+ protected def readTermName()(implicit ctx: Context): TermName = readName().toTermName
+ protected def readTypeName()(implicit ctx: Context): TypeName = readName().toTypeName
+
+ /** Read a symbol */
+ protected def readSymbol()(implicit ctx: Context): Symbol = readDisambiguatedSymbol(alwaysTrue)()
+
+ /** Read a symbol, with possible disambiguation */
+ protected def readDisambiguatedSymbol(p: Symbol => Boolean)()(implicit ctx: Context): Symbol = {
+ val start = indexCoord(readIndex)
+ val tag = readByte()
+ val end = readNat() + readIndex
+ def atEnd = readIndex == end
+
+ def readExtSymbol(): Symbol = {
+ val name = readNameRef()
+ val owner = if (atEnd) loadingMirror.RootClass else readSymbolRef()
+
+ def adjust(denot: Denotation) = {
+ val denot1 = denot.disambiguate(d => p(d.symbol))
+ val sym = denot1.symbol
+ if (denot.exists && !denot1.exists) { // !!!DEBUG
+ val alts = denot.alternatives map (d => d + ":" + d.info + "/" + d.signature)
+ System.err.println(s"!!! disambiguation failure: $alts")
+ val members = denot.alternatives.head.symbol.owner.info.decls.toList map (d => d + ":" + d.info + "/" + d.signature)
+ System.err.println(s"!!! all members: $members")
+ }
+ if (tag == EXTref) sym else sym.moduleClass
+ }
+
+ def fromName(name: Name): Symbol = name.toTermName match {
+ case nme.ROOT => loadingMirror.RootClass
+ case nme.ROOTPKG => loadingMirror.RootPackage
+ case _ =>
+ def declIn(owner: Symbol) = adjust(owner.info.decl(name))
+ val sym = declIn(owner)
+ if (sym.exists || owner.ne(defn.ObjectClass)) sym else declIn(defn.AnyClass)
+ }
+
+ def slowSearch(name: Name): Symbol =
+ owner.info.decls.find(_.name == name).getOrElse(NoSymbol)
+
+ def nestedObjectSymbol: Symbol = {
+ // If the owner is overloaded (i.e. a method), it's not possible to select the
+ // right member, so return NoSymbol. This can only happen when unpickling a tree.
+ // the "case Apply" in readTree() takes care of selecting the correct alternative
+ // after parsing the arguments.
+ //if (owner.isOverloaded)
+ // return NoSymbol
+
+ if (tag == EXTMODCLASSref) {
+ val module = owner.info.decl(name.toTermName).suchThat(_ is Module)
+ module.info // force it, as completer does not yet point to module class.
+ module.symbol.moduleClass
+
+ /* was:
+ val moduleVar = owner.info.decl(name.toTermName.moduleVarName).symbol
+ if (moduleVar.isLazyAccessor)
+ return moduleVar.lazyAccessor.lazyAccessor
+ */
+ } else NoSymbol
+ }
+
+ // println(s"read ext symbol $name from ${owner.denot.debugString} in ${classRoot.debugString}") // !!! DEBUG
+
+ // (1) Try name.
+ fromName(name) orElse {
+ // (2) Try with expanded name. Can happen if references to private
+ // symbols are read from outside: for instance when checking the children
+ // of a class. See #1722.
+ fromName(name.toTermName.expandedName(owner)) orElse {
+ // (3) Try as a nested object symbol.
+ nestedObjectSymbol orElse {
+ // (4) Call the mirror's "missing" hook.
+ adjust(ctx.base.missingHook(owner, name)) orElse {
+ // println(owner.info.decls.toList.map(_.debugString).mkString("\n ")) // !!! DEBUG
+ // }
+ // (5) Create a stub symbol to defer hard failure a little longer.
+ System.err.println(i"***** missing reference, looking for $name in $owner")
+ System.err.println(i"decls = ${owner.info.decls}")
+ owner.info.decls.checkConsistent()
+ if (slowSearch(name).exists)
+ System.err.println(i"**** slow search found: ${slowSearch(name)}")
+ if (ctx.debug) Thread.dumpStack()
+ ctx.newStubSymbol(owner, name, source)
+ }
+ }
+ }
+ }
+ }
+
+ tag match {
+ case NONEsym => return NoSymbol
+ case EXTref | EXTMODCLASSref => return readExtSymbol()
+ case _ =>
+ }
+
+ // symbols that were pickled with Pickler.writeSymInfo
+ val nameref = readNat()
+ val name0 = at(nameref, readName)
+ val owner = readSymbolRef()
+
+ var flags = unpickleScalaFlags(readLongNat(), name0.isTypeName)
+ if (flags is DefaultParameter) {
+ // DefaultParameterized flag now on method, not parameter
+ //assert(flags is Param, s"$name0 in $owner")
+ flags = flags &~ DefaultParameterized
+ owner.setFlag(DefaultParameterized)
+ }
+
+ val name1 = name0.adjustIfModuleClass(flags)
+ val name = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1
+
+ def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass)
+ def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module)
+ def isModuleRoot = (name == moduleClassRoot.name.sourceModuleName) && (owner == moduleClassRoot.owner) && (flags is Module)
+
+ //if (isClassRoot) println(s"classRoot of $classRoot found at $readIndex, flags = $flags") // !!! DEBUG
+ //if (isModuleRoot) println(s"moduleRoot of $moduleRoot found at $readIndex, flags = $flags") // !!! DEBUG
+ //if (isModuleClassRoot) println(s"moduleClassRoot of $moduleClassRoot found at $readIndex, flags = $flags") // !!! DEBUG
+
+ def completeRoot(denot: ClassDenotation, completer: LazyType): Symbol = {
+ denot.setFlag(flags)
+ denot.resetFlag(Touched) // allow one more completion
+ denot.info = completer
+ denot.symbol
+ }
+
+ def finishSym(sym: Symbol): Symbol = {
+ if (sym.isClass) sym.setFlag(Scala2x)
+ val owner = sym.owner
+ if (owner.isClass &&
+ !( isUnpickleRoot(sym)
+ || (sym is Scala2Existential)
+ || isRefinementClass(sym)
+ )
+ )
+ owner.asClass.enter(sym, symScope(owner))
+ else if (isRefinementClass(owner))
+ symScope(owner).openForMutations.enter(sym)
+ sym
+ }
+
+ finishSym(tag match {
+ case TYPEsym | ALIASsym =>
+ var name1 = name.asTypeName
+ var flags1 = flags
+ if (flags is TypeParam) {
+ name1 = name1.expandedName(owner)
+ flags1 |= owner.typeParamCreationFlags | ExpandedName
+ }
+ ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start)
+ case CLASSsym =>
+ var infoRef = readNat()
+ if (isSymbolRef(infoRef)) infoRef = readNat()
+ if (isClassRoot)
+ completeRoot(
+ classRoot, rootClassUnpickler(start, classRoot.symbol, NoSymbol, infoRef))
+ else if (isModuleClassRoot)
+ completeRoot(
+ moduleClassRoot, rootClassUnpickler(start, moduleClassRoot.symbol, moduleClassRoot.sourceModule, infoRef))
+ else if (name == tpnme.REFINE_CLASS)
+ // create a type alias instead
+ ctx.newSymbol(owner, name, flags, localMemberUnpickler, coord = start)
+ else {
+ def completer(cls: Symbol) = {
+ val unpickler = new ClassUnpickler(infoRef) withDecls symScope(cls)
+ if (flags is ModuleClass)
+ unpickler withSourceModule (implicit ctx =>
+ cls.owner.info.decls.lookup(cls.name.sourceModuleName)
+ .suchThat(_ is Module).symbol)
+ else unpickler
+ }
+ ctx.newClassSymbol(owner, name.asTypeName, flags, completer, coord = start)
+ }
+ case VALsym =>
+ ctx.newSymbol(owner, name.asTermName, flags, localMemberUnpickler, coord = start)
+ case MODULEsym =>
+ if (isModuleRoot) {
+ moduleRoot setFlag flags
+ moduleRoot.symbol
+ } else ctx.newSymbol(owner, name.asTermName, flags,
+ new LocalUnpickler() withModuleClass(implicit ctx =>
+ owner.info.decls.lookup(name.moduleClassName)
+ .suchThat(_ is Module).symbol)
+ , coord = start)
+ case _ =>
+ errorBadSignature("bad symbol tag: " + tag)
+ })
+ }
+
+ class LocalUnpickler extends LazyType {
+ def startCoord(denot: SymDenotation): Coord = denot.symbol.coord
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = try {
+ def parseToCompletion(denot: SymDenotation)(implicit ctx: Context) = {
+ val tag = readByte()
+ val end = readNat() + readIndex
+ def atEnd = readIndex == end
+ val unusedNameref = readNat()
+ val unusedOwnerref = readNat()
+ val unusedFlags = readLongNat()
+ var inforef = readNat()
+ denot.privateWithin =
+ if (!isSymbolRef(inforef)) NoSymbol
+ else {
+ val pw = at(inforef, readSymbol)
+ inforef = readNat()
+ pw
+ }
+ // println("reading type for " + denot) // !!! DEBUG
+ val tp = at(inforef, readType)
+ denot match {
+ case denot: ClassDenotation =>
+ val selfInfo = if (atEnd) NoType else readTypeRef()
+ setClassInfo(denot, tp, selfInfo)
+ case denot =>
+ val tp1 = translateTempPoly(tp)
+ denot.info =
+ if (tag == ALIASsym) TypeAlias(tp1)
+ else if (denot.isType) checkNonCyclic(denot.symbol, tp1, reportErrors = false)
+ // we need the checkNonCyclic call to insert LazyRefs for F-bounded cycles
+ else if (!denot.is(Param)) tp1.underlyingIfRepeated(isJava = false)
+ else tp1
+ if (denot.isConstructor) addConstructorTypeParams(denot)
+ if (atEnd) {
+ assert(!(denot is SuperAccessor), denot)
+ } else {
+ assert(denot is (SuperAccessor | ParamAccessor), denot)
+ def disambiguate(alt: Symbol) = { // !!! DEBUG
+ ctx.debugTraceIndented(s"disambiguating ${denot.info} =:= ${denot.owner.thisType.memberInfo(alt)} ${denot.owner}") {
+ denot.info matches denot.owner.thisType.memberInfo(alt)
+ }
+ }
+ val alias = readDisambiguatedSymbolRef(disambiguate).asTerm
+ denot.addAnnotation(Annotation.makeAlias(alias))
+ }
+ }
+ // println(s"unpickled ${denot.debugString}, info = ${denot.info}") !!! DEBUG
+ }
+ atReadPos(startCoord(denot).toIndex,
+ () => parseToCompletion(denot)(
+ ctx.addMode(Mode.Scala2Unpickling).withPhaseNoLater(ctx.picklerPhase)))
+ } catch {
+ case ex: RuntimeException => handleRuntimeException(ex)
+ }
+ }
+
+ object localMemberUnpickler extends LocalUnpickler
+
+ class ClassUnpickler(infoRef: Int) extends LocalUnpickler with TypeParamsCompleter {
+ private def readTypeParams()(implicit ctx: Context): List[TypeSymbol] = {
+ val tag = readByte()
+ val end = readNat() + readIndex
+ if (tag == POLYtpe) {
+ val unusedRestpeRef = readNat()
+ until(end, readSymbolRef).asInstanceOf[List[TypeSymbol]]
+ } else Nil
+ }
+ private def loadTypeParams(implicit ctx: Context) =
+ atReadPos(index(infoRef), readTypeParams)
+
+ /** Force reading type params early, we need them in setClassInfo of subclasses. */
+ def init()(implicit ctx: Context) = loadTypeParams
+
+ def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] =
+ loadTypeParams
+ }
+
+ def rootClassUnpickler(start: Coord, cls: Symbol, module: Symbol, infoRef: Int) =
+ (new ClassUnpickler(infoRef) with SymbolLoaders.SecondCompleter {
+ override def startCoord(denot: SymDenotation): Coord = start
+ }) withDecls symScope(cls) withSourceModule (_ => module)
+
+ /** Convert
+ * tp { type name = sym } forSome { sym >: L <: H }
+ * to
+ * tp { name >: L <: H }
+ * and
+ * tp { name: sym } forSome { sym <: T with Singleton }
+ * to
+ * tp { name: T }
+ */
+ def elimExistentials(boundSyms: List[Symbol], tp: Type)(implicit ctx: Context): Type = {
+ // Need to be careful not to run into cyclic references here (observed when
+ // comiling t247.scala). That's why we avoiud taking `symbol` of a TypeRef
+ // unless names match up.
+ val isBound = (tp: Type) => {
+ def refersTo(tp: Type, sym: Symbol): Boolean = tp match {
+ case tp @ TypeRef(_, name) => sym.name == name && sym == tp.symbol
+ case tp: TypeVar => refersTo(tp.underlying, sym)
+ case tp : LazyRef => refersTo(tp.ref, sym)
+ case _ => false
+ }
+ boundSyms.exists(refersTo(tp, _))
+ }
+ // Cannot use standard `existsPart` method because it calls `lookupRefined`
+ // which can cause CyclicReference errors.
+ val isBoundAccumulator = new ExistsAccumulator(isBound) {
+ override def foldOver(x: Boolean, tp: Type): Boolean = tp match {
+ case tp: TypeRef => applyToPrefix(x, tp)
+ case _ => super.foldOver(x, tp)
+ }
+ }
+ def removeSingleton(tp: Type): Type =
+ if (tp isRef defn.SingletonClass) defn.AnyType else tp
+ def elim(tp: Type): Type = tp match {
+ case tp @ RefinedType(parent, name, rinfo) =>
+ val parent1 = elim(tp.parent)
+ rinfo match {
+ case TypeAlias(info: TypeRef) if isBound(info) =>
+ RefinedType(parent1, name, info.symbol.info)
+ case info: TypeRef if isBound(info) =>
+ val info1 = info.symbol.info
+ assert(info1.derivesFrom(defn.SingletonClass))
+ RefinedType(parent1, name, info1.mapReduceAnd(removeSingleton)(_ & _))
+ case info =>
+ tp.derivedRefinedType(parent1, name, info)
+ }
+ case tp @ HKApply(tycon, args) =>
+ val tycon1 = tycon.safeDealias
+ def mapArg(arg: Type) = arg match {
+ case arg: TypeRef if isBound(arg) => arg.symbol.info
+ case _ => arg
+ }
+ if (tycon1 ne tycon) elim(tycon1.appliedTo(args))
+ else tp.derivedAppliedType(tycon, args.map(mapArg))
+ case _ =>
+ tp
+ }
+ val tp1 = elim(tp)
+ if (isBoundAccumulator(false, tp1)) {
+ val anyTypes = boundSyms map (_ => defn.AnyType)
+ val boundBounds = boundSyms map (_.info.bounds.hi)
+ val tp2 = tp1.subst(boundSyms, boundBounds).subst(boundSyms, anyTypes)
+ ctx.warning(s"""failure to eliminate existential
+ |original type : $tp forSome {${ctx.dclsText(boundSyms, "; ").show}
+ |reduces to : $tp1
+ |type used instead: $tp2
+ |proceed at own risk.""".stripMargin)
+ tp2
+ } else tp1
+ }
+
+ /** Read a type
+ *
+ * @param forceProperType is used to ease the transition to NullaryMethodTypes (commentmarker: NMT_TRANSITION)
+ * the flag say that a type of kind * is expected, so that PolyType(tps, restpe) can be disambiguated to PolyType(tps, NullaryMethodType(restpe))
+ * (if restpe is not a ClassInfoType, a MethodType or a NullaryMethodType, which leaves TypeRef/SingletonType -- the latter would make the polytype a type constructor)
+ */
+ protected def readType()(implicit ctx: Context): Type = {
+ val tag = readByte()
+ val end = readNat() + readIndex
+ (tag: @switch) match {
+ case NOtpe =>
+ NoType
+ case NOPREFIXtpe =>
+ NoPrefix
+ case THIStpe =>
+ readSymbolRef().thisType
+ case SINGLEtpe =>
+ val pre = readTypeRef()
+ val sym = readDisambiguatedSymbolRef(_.info.isParameterless)
+ if (isLocal(sym) || (pre == NoPrefix)) pre select sym
+ else TermRef.withSig(pre, sym.name.asTermName, Signature.NotAMethod) // !!! should become redundant
+ case SUPERtpe =>
+ val thistpe = readTypeRef()
+ val supertpe = readTypeRef()
+ SuperType(thistpe, supertpe)
+ case CONSTANTtpe =>
+ ConstantType(readConstantRef())
+ case TYPEREFtpe =>
+ var pre = readTypeRef()
+ val sym = readSymbolRef()
+ pre match {
+ case thispre: ThisType =>
+ // The problem is that class references super.C get pickled as
+ // this.C. Dereferencing the member might then get an overriding class
+ // instance. The problem arises for instance for LinkedHashMap#MapValues
+ // and also for the inner Transform class in all views. We fix it by
+ // replacing the this with the appropriate super.
+ if (sym.owner != thispre.cls) {
+ val overriding = thispre.cls.info.decls.lookup(sym.name)
+ if (overriding.exists && overriding != sym) {
+ val base = pre.baseTypeWithArgs(sym.owner)
+ assert(base.exists)
+ pre = SuperType(thispre, base)
+ }
+ }
+ case _ =>
+ }
+ val tycon =
+ if (sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package))
+ // used fixed sym for Scala 2 inner classes, because they might be shadowed
+ TypeRef.withFixedSym(pre, sym.name.asTypeName, sym.asType)
+ else if (isLocal(sym) || pre == NoPrefix) {
+ val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre
+ pre1 select sym
+ }
+ else TypeRef(pre, sym.name.asTypeName)
+ val args = until(end, readTypeRef)
+ if (sym == defn.ByNameParamClass2x) ExprType(args.head)
+ else if (args.nonEmpty) tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args))
+ else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
+ else tycon
+ case TYPEBOUNDStpe =>
+ TypeBounds(readTypeRef(), readTypeRef())
+ case REFINEDtpe =>
+ val clazz = readSymbolRef()
+ val decls = symScope(clazz)
+ symScopes(clazz) = EmptyScope // prevent further additions
+ val parents = until(end, readTypeRef)
+ val parent = parents.reduceLeft(AndType(_, _))
+ if (decls.isEmpty) parent
+ else {
+ def subst(info: Type, rt: RecType) =
+ if (clazz.isClass) info.substThis(clazz.asClass, RecThis(rt))
+ else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case.
+ def addRefinement(tp: Type, sym: Symbol) = RefinedType(tp, sym.name, sym.info)
+ val refined = (parent /: decls.toList)(addRefinement)
+ RecType.closeOver(rt => subst(refined, rt))
+ }
+ case CLASSINFOtpe =>
+ val clazz = readSymbolRef()
+ TempClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
+ case METHODtpe | IMPLICITMETHODtpe =>
+ val restpe = readTypeRef()
+ val params = until(end, readSymbolRef)
+ def isImplicit =
+ tag == IMPLICITMETHODtpe ||
+ params.nonEmpty && (params.head is Implicit)
+ val maker = if (isImplicit) ImplicitMethodType else MethodType
+ maker.fromSymbols(params, restpe)
+ case POLYtpe =>
+ val restpe = readTypeRef()
+ val typeParams = until(end, readSymbolRef)
+ if (typeParams.nonEmpty) TempPolyType(typeParams.asInstanceOf[List[TypeSymbol]], restpe.widenExpr)
+ else ExprType(restpe)
+ case EXISTENTIALtpe =>
+ val restpe = readTypeRef()
+ val boundSyms = until(end, readSymbolRef)
+ elimExistentials(boundSyms, restpe)
+ case ANNOTATEDtpe =>
+ AnnotatedType.make(readTypeRef(), until(end, readAnnotationRef))
+ case _ =>
+ noSuchTypeTag(tag, end)
+ }
+ }
+
+ def readTypeParams()(implicit ctx: Context): List[Symbol] = {
+ val tag = readByte()
+ val end = readNat() + readIndex
+ if (tag == POLYtpe) {
+ val unusedRestperef = readNat()
+ until(end, readSymbolRef)
+ } else Nil
+ }
+
+ def noSuchTypeTag(tag: Int, end: Int)(implicit ctx: Context): Type =
+ errorBadSignature("bad type tag: " + tag)
+
+ /** Read a constant */
+ protected def readConstant()(implicit ctx: Context): Constant = {
+ val tag = readByte().toInt
+ val len = readNat()
+ (tag: @switch) match {
+ case LITERALunit => Constant(())
+ case LITERALboolean => Constant(readLong(len) != 0L)
+ case LITERALbyte => Constant(readLong(len).toByte)
+ case LITERALshort => Constant(readLong(len).toShort)
+ case LITERALchar => Constant(readLong(len).toChar)
+ case LITERALint => Constant(readLong(len).toInt)
+ case LITERALlong => Constant(readLong(len))
+ case LITERALfloat => Constant(intBitsToFloat(readLong(len).toInt))
+ case LITERALdouble => Constant(longBitsToDouble(readLong(len)))
+ case LITERALstring => Constant(readNameRef().toString)
+ case LITERALnull => Constant(null)
+ case LITERALclass => Constant(readTypeRef())
+ case LITERALenum => Constant(readSymbolRef())
+ case _ => noSuchConstantTag(tag, len)
+ }
+ }
+
+ def noSuchConstantTag(tag: Int, len: Int)(implicit ctx: Context): Constant =
+ errorBadSignature("bad constant tag: " + tag)
+
+ /** Read children and store them into the corresponding symbol.
+ */
+ protected def readChildren()(implicit ctx: Context): Unit = {
+ val tag = readByte()
+ assert(tag == CHILDREN)
+ val end = readNat() + readIndex
+ val target = readSymbolRef()
+ while (readIndex != end)
+ target.addAnnotation(Annotation.makeChild(readSymbolRef()))
+ }
+
+ /* Read a reference to a pickled item */
+ protected def readSymbolRef()(implicit ctx: Context): Symbol = { //OPT inlined from: at(readNat(), readSymbol) to save on closure creation
+ val i = readNat()
+ var r = entries(i)
+ if (r eq null) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ r = readSymbol()
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ readIndex = savedIndex
+ }
+ r.asInstanceOf[Symbol]
+ }
+
+ protected def readDisambiguatedSymbolRef(p: Symbol => Boolean)(implicit ctx: Context): Symbol =
+ at(readNat(), readDisambiguatedSymbol(p))
+
+ protected def readNameRef()(implicit ctx: Context): Name = at(readNat(), readName)
+ protected def readTypeRef()(implicit ctx: Context): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
+ protected def readConstantRef()(implicit ctx: Context): Constant = at(readNat(), readConstant)
+
+ protected def readTypeNameRef()(implicit ctx: Context): TypeName = readNameRef().toTypeName
+ protected def readTermNameRef()(implicit ctx: Context): TermName = readNameRef().toTermName
+
+ protected def readAnnotationRef()(implicit ctx: Context): Annotation = at(readNat(), readAnnotation)
+
+ protected def readModifiersRef(isType: Boolean)(implicit ctx: Context): Modifiers = at(readNat(), () => readModifiers(isType))
+ protected def readTreeRef()(implicit ctx: Context): Tree = at(readNat(), readTree)
+
+ /** Read an annotation argument, which is pickled either
+ * as a Constant or a Tree.
+ */
+ protected def readAnnotArg(i: Int)(implicit ctx: Context): Tree = bytes(index(i)) match {
+ case TREE => at(i, readTree)
+ case _ => Literal(at(i, readConstant))
+ }
+
+ /** Read a ClassfileAnnotArg (argument to a classfile annotation)
+ */
+ private def readArrayAnnotArg()(implicit ctx: Context): Tree = {
+ readByte() // skip the `annotargarray` tag
+ val end = readNat() + readIndex
+ // array elements are trees representing instances of scala.annotation.Annotation
+ SeqLiteral(
+ until(end, () => readClassfileAnnotArg(readNat())),
+ TypeTree(defn.AnnotationType))
+ }
+
+ private def readAnnotInfoArg()(implicit ctx: Context): Tree = {
+ readByte() // skip the `annotinfo` tag
+ val end = readNat() + readIndex
+ readAnnotationContents(end)
+ }
+
+ protected def readClassfileAnnotArg(i: Int)(implicit ctx: Context): Tree = bytes(index(i)) match {
+ case ANNOTINFO => at(i, readAnnotInfoArg)
+ case ANNOTARGARRAY => at(i, readArrayAnnotArg)
+ case _ => readAnnotArg(i)
+ }
+
+ /** Read an annotation's contents. Not to be called directly, use
+ * readAnnotation, readSymbolAnnotation, or readAnnotInfoArg
+ */
+ protected def readAnnotationContents(end: Int)(implicit ctx: Context): Tree = {
+ val atp = readTypeRef()
+ val args = {
+ val t = new ListBuffer[Tree]
+
+ while (readIndex != end) {
+ val argref = readNat()
+ t += {
+ if (isNameEntry(argref)) {
+ val name = at(argref, readName)
+ val arg = readClassfileAnnotArg(readNat())
+ NamedArg(name.asTermName, arg)
+ } else readAnnotArg(argref)
+ }
+ }
+ t.toList
+ }
+ // println(atp)
+ val targs = atp.argTypes
+
+ tpd.applyOverloaded(tpd.New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp)
+}
+
+ /** Read an annotation and as a side effect store it into
+ * the symbol it requests. Called at top-level, for all
+ * (symbol, annotInfo) entries.
+ */
+ protected def readSymbolAnnotation()(implicit ctx: Context): Unit = {
+ val tag = readByte()
+ if (tag != SYMANNOT)
+ errorBadSignature("symbol annotation expected (" + tag + ")")
+ val end = readNat() + readIndex
+ val target = readSymbolRef()
+ target.addAnnotation(deferredAnnot(end))
+ }
+
+ /** Read an annotation and return it. Used when unpickling
+ * an ANNOTATED(WSELF)tpe or a NestedAnnotArg
+ */
+ protected def readAnnotation()(implicit ctx: Context): Annotation = {
+ val tag = readByte()
+ if (tag != ANNOTINFO)
+ errorBadSignature("annotation expected (" + tag + ")")
+ val end = readNat() + readIndex
+ deferredAnnot(end)
+ }
+
+ /** A deferred annotation that can be completed by reading
+ * the bytes between `readIndex` and `end`.
+ */
+ protected def deferredAnnot(end: Int)(implicit ctx: Context): Annotation = {
+ val start = readIndex
+ val atp = readTypeRef()
+ Annotation.deferred(
+ atp.typeSymbol, implicit ctx1 =>
+ atReadPos(start, () => readAnnotationContents(end)(ctx1.withPhase(ctx.phase))))
+ }
+
+ /* Read an abstract syntax tree */
+ protected def readTree()(implicit ctx: Context): Tree = {
+ val outerTag = readByte()
+ if (outerTag != TREE)
+ errorBadSignature("tree expected (" + outerTag + ")")
+ val end = readNat() + readIndex
+ val tag = readByte()
+ val tpe = if (tag == EMPTYtree) NoType else readTypeRef()
+
+ // Set by the three functions to follow. If symbol is non-null
+ // after the new tree 't' has been created, t has its Symbol
+ // set to symbol; and it always has its Type set to tpe.
+ var symbol: Symbol = null
+ var mods: Modifiers = null
+ var name: Name = null
+
+ /** Read a Symbol, Modifiers, and a Name */
+ def setSymModsName(): Unit = {
+ symbol = readSymbolRef()
+ mods = readModifiersRef(symbol.isType)
+ name = readNameRef()
+ }
+ /** Read a Symbol and a Name */
+ def setSymName(): Unit = {
+ symbol = readSymbolRef()
+ name = readNameRef()
+ }
+ /** Read a Symbol */
+ def setSym(): Unit = {
+ symbol = readSymbolRef()
+ }
+
+ implicit val pos: Position = NoPosition
+
+ tag match {
+ case EMPTYtree =>
+ EmptyTree
+
+ case PACKAGEtree =>
+ setSym()
+ val pid = readTreeRef().asInstanceOf[RefTree]
+ val stats = until(end, readTreeRef)
+ PackageDef(pid, stats)
+
+ case CLASStree =>
+ setSymModsName()
+ val impl = readTemplateRef()
+ val tparams = until(end, readTypeDefRef)
+ val cls = symbol.asClass
+ val ((constr: DefDef) :: Nil, stats) =
+ impl.body.partition(_.symbol == cls.primaryConstructor)
+ ClassDef(cls, constr, tparams ++ stats)
+
+ case MODULEtree =>
+ setSymModsName()
+ ModuleDef(symbol.asTerm, readTemplateRef().body)
+
+ case VALDEFtree =>
+ setSymModsName()
+ val tpt = readTreeRef()
+ val rhs = readTreeRef()
+ ValDef(symbol.asTerm, rhs)
+
+ case DEFDEFtree =>
+ setSymModsName()
+ val tparams = times(readNat(), readTypeDefRef)
+ val vparamss = times(readNat(), () => times(readNat(), readValDefRef))
+ val tpt = readTreeRef()
+ val rhs = readTreeRef()
+ DefDef(symbol.asTerm, rhs)
+
+ case TYPEDEFtree =>
+ setSymModsName()
+ val rhs = readTreeRef()
+ val tparams = until(end, readTypeDefRef)
+ TypeDef(symbol.asType)
+
+ case LABELtree =>
+ setSymName()
+ val rhs = readTreeRef()
+ val params = until(end, readIdentRef)
+ val ldef = DefDef(symbol.asTerm, rhs)
+ def isCaseLabel(sym: Symbol) = sym.name.startsWith(nme.CASEkw)
+ if (isCaseLabel(symbol)) ldef
+ else Block(ldef :: Nil, Apply(Ident(symbol.termRef), Nil))
+
+ case IMPORTtree =>
+ setSym()
+ val expr = readTreeRef()
+ val selectors = until(end, () => {
+ val fromName = readNameRef()
+ val toName = readNameRef()
+ val from = untpd.Ident(fromName)
+ val to = untpd.Ident(toName)
+ if (toName.isEmpty) from else untpd.Thicket(from, untpd.Ident(toName))
+ })
+
+ Import(expr, selectors)
+
+ case TEMPLATEtree =>
+ setSym()
+ val parents = times(readNat(), readTreeRef)
+ val self = readValDefRef()
+ val body = until(end, readTreeRef)
+ untpd.Template(???, parents, self, body) // !!! TODO: pull out primary constructor
+ .withType(symbol.namedType)
+
+ case BLOCKtree =>
+ val expr = readTreeRef()
+ val stats = until(end, readTreeRef)
+ Block(stats, expr)
+
+ case CASEtree =>
+ val pat = readTreeRef()
+ val guard = readTreeRef()
+ val body = readTreeRef()
+ CaseDef(pat, guard, body)
+
+ case ALTERNATIVEtree =>
+ Alternative(until(end, readTreeRef))
+
+ case STARtree =>
+ readTreeRef()
+ unimplementedTree("STAR")
+
+ case BINDtree =>
+ setSymName()
+ Bind(symbol.asTerm, readTreeRef())
+
+ case UNAPPLYtree =>
+ val fun = readTreeRef()
+ val args = until(end, readTreeRef)
+ UnApply(fun, Nil, args, defn.AnyType) // !!! this is wrong in general
+
+ case ARRAYVALUEtree =>
+ val elemtpt = readTreeRef()
+ val trees = until(end, readTreeRef)
+ SeqLiteral(trees, elemtpt)
+ // note can't deal with trees passed to Java methods as arrays here
+
+ case FUNCTIONtree =>
+ setSym()
+ val body = readTreeRef()
+ val vparams = until(end, readValDefRef)
+ val applyType = MethodType(vparams map (_.name), vparams map (_.tpt.tpe), body.tpe)
+ val applyMeth = ctx.newSymbol(symbol.owner, nme.apply, Method, applyType)
+ Closure(applyMeth, Function.const(body.changeOwner(symbol, applyMeth)) _)
+
+ case ASSIGNtree =>
+ val lhs = readTreeRef()
+ val rhs = readTreeRef()
+ Assign(lhs, rhs)
+
+ case IFtree =>
+ val cond = readTreeRef()
+ val thenp = readTreeRef()
+ val elsep = readTreeRef()
+ If(cond, thenp, elsep)
+
+ case MATCHtree =>
+ val selector = readTreeRef()
+ val cases = until(end, readCaseDefRef)
+ Match(selector, cases)
+
+ case RETURNtree =>
+ setSym()
+ Return(readTreeRef(), Ident(symbol.termRef))
+
+ case TREtree =>
+ val block = readTreeRef()
+ val finalizer = readTreeRef()
+ val catches = until(end, readCaseDefRef)
+ Try(block, catches, finalizer)
+
+ case THROWtree =>
+ Throw(readTreeRef())
+
+ case NEWtree =>
+ New(readTreeRef().tpe)
+
+ case TYPEDtree =>
+ val expr = readTreeRef()
+ val tpt = readTreeRef()
+ Typed(expr, tpt)
+
+ case TYPEAPPLYtree =>
+ val fun = readTreeRef()
+ val args = until(end, readTreeRef)
+ TypeApply(fun, args)
+
+ case APPLYtree =>
+ val fun = readTreeRef()
+ val args = until(end, readTreeRef)
+ /*
+ if (fun.symbol.isOverloaded) {
+ fun.setType(fun.symbol.info)
+ inferMethodAlternative(fun, args map (_.tpe), tpe)
+ }
+*/
+ Apply(fun, args) // note: can't deal with overloaded syms yet
+
+ case APPLYDYNAMICtree =>
+ setSym()
+ val qual = readTreeRef()
+ val args = until(end, readTreeRef)
+ unimplementedTree("APPLYDYNAMIC")
+
+ case SUPERtree =>
+ setSym()
+ val qual = readTreeRef()
+ val mix = readTypeNameRef()
+ Super(qual, mix, inConstrCall = false) // todo: revise
+
+ case THIStree =>
+ setSym()
+ val name = readTypeNameRef()
+ This(symbol.asClass)
+
+ case SELECTtree =>
+ setSym()
+ val qualifier = readTreeRef()
+ val selector = readNameRef()
+ qualifier.select(symbol.namedType)
+ case IDENTtree =>
+ setSymName()
+ Ident(symbol.namedType)
+
+ case LITERALtree =>
+ Literal(readConstantRef())
+
+ case TYPEtree =>
+ TypeTree(tpe)
+
+ case ANNOTATEDtree =>
+ val annot = readTreeRef()
+ val arg = readTreeRef()
+ Annotated(arg, annot)
+
+ case SINGLETONTYPEtree =>
+ SingletonTypeTree(readTreeRef())
+
+ case SELECTFROMTYPEtree =>
+ val qualifier = readTreeRef()
+ val selector = readTypeNameRef()
+ Select(qualifier, symbol.namedType)
+
+ case COMPOUNDTYPEtree =>
+ readTemplateRef()
+ TypeTree(tpe)
+
+ case APPLIEDTYPEtree =>
+ val tpt = readTreeRef()
+ val args = until(end, readTreeRef)
+ AppliedTypeTree(tpt, args)
+
+ case TYPEBOUNDStree =>
+ val lo = readTreeRef()
+ val hi = readTreeRef()
+ TypeBoundsTree(lo, hi)
+
+ case EXISTENTIALTYPEtree =>
+ val tpt = readTreeRef()
+ val whereClauses = until(end, readTreeRef)
+ TypeTree(tpe)
+
+ case _ =>
+ noSuchTreeTag(tag, end)
+ }
+ }
+
+ def noSuchTreeTag(tag: Int, end: Int)(implicit ctx: Context) =
+ errorBadSignature("unknown tree type (" + tag + ")")
+
+ def unimplementedTree(what: String)(implicit ctx: Context) =
+ errorBadSignature(s"cannot read $what trees from Scala 2.x signatures")
+
+ def readModifiers(isType: Boolean)(implicit ctx: Context): Modifiers = {
+ val tag = readNat()
+ if (tag != MODIFIERS)
+ errorBadSignature("expected a modifiers tag (" + tag + ")")
+ val end = readNat() + readIndex
+ val pflagsHi = readNat()
+ val pflagsLo = readNat()
+ val pflags = (pflagsHi.toLong << 32) + pflagsLo
+ val flags = unpickleScalaFlags(pflags, isType)
+ val privateWithin = readNameRef().asTypeName
+ Modifiers(flags, privateWithin, Nil)
+ }
+
+ protected def readTemplateRef()(implicit ctx: Context): Template =
+ readTreeRef() match {
+ case templ: Template => templ
+ case other =>
+ errorBadSignature("expected a template (" + other + ")")
+ }
+ protected def readCaseDefRef()(implicit ctx: Context): CaseDef =
+ readTreeRef() match {
+ case tree: CaseDef => tree
+ case other =>
+ errorBadSignature("expected a case def (" + other + ")")
+ }
+ protected def readValDefRef()(implicit ctx: Context): ValDef =
+ readTreeRef() match {
+ case tree: ValDef => tree
+ case other =>
+ errorBadSignature("expected a ValDef (" + other + ")")
+ }
+ protected def readIdentRef()(implicit ctx: Context): Ident =
+ readTreeRef() match {
+ case tree: Ident => tree
+ case other =>
+ errorBadSignature("expected an Ident (" + other + ")")
+ }
+ protected def readTypeDefRef()(implicit ctx: Context): TypeDef =
+ readTreeRef() match {
+ case tree: TypeDef => tree
+ case other =>
+ errorBadSignature("expected an TypeDef (" + other + ")")
+ }
+
+}