scala.reflect.generic.UnPickler.scala Maven / Gradle / Ivy
/* NSC -- new Scala compiler
* Copyright 2005-2010 LAMP/EPFL
* @author Martin Odersky
*/
package scala.reflect
package generic
import java.io.IOException
import java.lang.{Float, Double}
import Flags._
import PickleFormat._
import collection.mutable.{HashMap, ListBuffer}
import annotation.switch
/** @author Martin Odersky
* @version 1.0
*/
abstract class UnPickler {
val global: Universe
import global._
/** 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 offset offset from which unpickling starts
* @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable
* @param moduleroot the top-level module which is unpickled, or NoSymbol if inapplicable
* @param filename filename associated with bytearray, only used for error messages
*/
def unpickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) {
try {
scan(bytes, offset, classRoot, moduleRoot, filename)
} catch {
case ex: IOException =>
throw ex
case ex: Throwable =>
/*if (settings.debug.value)*/ ex.printStackTrace()
throw new RuntimeException("error reading Scala signature of "+filename+": "+ex.getMessage())
}
}
/** To be implemented in subclasses. Like `unpickle` but without the catch-all error handling.
*/
def scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String)
abstract class Scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(bytes, offset, -1) {
//println("unpickle " + classRoot + " and " + moduleRoot)//debug
protected def debug = false
checkVersion()
/** 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 = new HashMap[Symbol, Scope]
//println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
def run() {
for (i <- 0 until index.length) {
if (isSymbolEntry(i))
at(i, readSymbol)
else if (isSymbolAnnotationEntry(i))
at(i, {() => readSymbolAnnotation(); null})
else if (isChildrenEntry(i))
at(i, {() => readChildren(); null})
}
}
private def checkVersion() {
val major = readNat()
val minor = readNat()
if (major != MajorVersion || minor > MinorVersion)
throw new IOException("Scala signature " + classRoot.decodedName +
" has wrong version\n expected: " +
MajorVersion + "." + MinorVersion +
"\n found: " + major + "." + minor +
" in "+filename)
}
/** The `decls' scope associated with given symbol */
protected def symScope(sym: Symbol) = symScopes.get(sym) match {
case None => val s = newScope; symScopes(sym) = s; s
case Some(s) => s
}
/** Does entry represent an (internal) symbol */
protected def isSymbolEntry(i: Int): 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): Boolean = {
val savedIndex = readIndex
readIndex = index(i)
val tag = readByte().toInt
assert(tag == CLASSsym)
readNat(); // read length
val result = readNameRef() == mkTypeName(nme.REFINE_CLASS_NAME)
readIndex = savedIndex
result
}
/** If entry at i is undefined, define it by performing
* operation op with readIndex at start of i'th
* entry. Restore readIndex afterwards.
*/
protected def at[T <: AnyRef](i: Int, op: () => T): T = {
var r = entries(i)
if (r eq null) {
val savedIndex = readIndex
readIndex = index(i)
r = op()
assert(entries(i) eq null, entries(i))
entries(i) = r
readIndex = savedIndex
}
r.asInstanceOf[T]
}
/** Read a name */
protected def readName(): Name = {
val tag = readByte()
val len = readNat()
tag match {
case TERMname => newTermName(bytes, readIndex, len)
case TYPEname => newTypeName(bytes, readIndex, len)
case _ => errorBadSignature("bad name tag: " + tag)
}
}
/** Read a symbol */
protected def readSymbol(): Symbol = {
val tag = readByte()
val end = readNat() + readIndex
var sym: Symbol = NoSymbol
tag match {
case EXTref | EXTMODCLASSref =>
val name = readNameRef()
val owner = if (readIndex == end) definitions.RootClass else readSymbolRef()
def fromName(name: Name) =
if (mkTermName(name) == nme.ROOT) definitions.RootClass
else if (name == nme.ROOTPKG) definitions.RootPackage
else if (tag == EXTref) owner.info.decl(name)
else owner.info.decl(name).moduleClass
sym = fromName(name)
// If sym not found try with expanded name.
// This can happen if references to private symbols are
// read from outside; for instance when checking the children of a class
// (see t1722)
if (sym == NoSymbol) sym = fromName(nme.expandedName(name, owner))
// If the owner is overloaded (i.e. a method), it's not possible to select the
// right member => 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 (sym == NoSymbol && !owner.isOverloaded) errorMissingRequirement(name, owner)
case NONEsym =>
sym = NoSymbol
case _ => // symbols that were pickled with Pickler.writeSymInfo
var defaultGetter: Symbol = NoSymbol // @deprecated, to be removed for 2.8 final
var nameref = readNat()
if (tag == VALsym && isSymbolRef(nameref)) { // @deprecated, to be removed for 2.8 final
defaultGetter = at(nameref, readSymbol)
nameref = readNat()
}
val name = at(nameref, readName)
val owner = readSymbolRef()
val flags = pickledToRawFlags(readLongNat())
var privateWithin: Symbol = NoSymbol
var inforef = readNat()
if (isSymbolRef(inforef)) {
privateWithin = at(inforef, readSymbol)
inforef = readNat()
}
tag match {
case TYPEsym =>
sym = owner.newAbstractType(name)
case ALIASsym =>
sym = owner.newAliasType(name)
case CLASSsym =>
sym =
if (name == classRoot.name && owner == classRoot.owner)
(if ((flags & MODULE) != 0L) moduleRoot.moduleClass
else classRoot)
else
if ((flags & MODULE) != 0L) owner.newModuleClass(name)
else owner.newClass(name)
if (readIndex != end) sym.typeOfThis = newLazyTypeRef(readNat())
case MODULEsym =>
val clazz = at(inforef, readType).typeSymbol
sym =
if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot
else {
val m = owner.newModule(name, clazz)
clazz.sourceModule = m
m
}
case VALsym =>
sym = if (name == moduleRoot.name && owner == moduleRoot.owner) { assert(false); NoSymbol }
else if ((flags & METHOD) != 0) owner.newMethod(name)
else owner.newValue(name)
case _ =>
noSuchSymbolTag(tag, end, name, owner)
}
sym.flags = flags & PickledFlags
sym.privateWithin = privateWithin
if (readIndex != end) assert(sym hasFlag (SUPERACCESSOR | PARAMACCESSOR), sym)
if (sym hasFlag SUPERACCESSOR) assert(readIndex != end)
sym.info =
if (readIndex != end) newLazyTypeRefAndAlias(inforef, readNat())
else newLazyTypeRef(inforef)
if (sym.owner.isClass && sym != classRoot && sym != moduleRoot &&
!sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound)
symScope(sym.owner) enter sym
}
sym
}
def noSuchSymbolTag(tag: Int, end: Int, name: Name, owner: Symbol) =
errorBadSignature("bad symbol tag: " + tag)
/** Read a type */
protected def readType(): Type = {
val tag = readByte()
val end = readNat() + readIndex
(tag: @switch) match {
case NOtpe =>
NoType
case NOPREFIXtpe =>
NoPrefix
case THIStpe =>
ThisType(readSymbolRef())
case SINGLEtpe =>
SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType
case SUPERtpe =>
val thistpe = readTypeRef()
val supertpe = readTypeRef()
SuperType(thistpe, supertpe)
case CONSTANTtpe =>
ConstantType(readConstantRef())
case TYPEREFtpe =>
val pre = readTypeRef()
val sym = readSymbolRef()
var args = until(end, readTypeRef)
TypeRef(pre, sym, args)
case TYPEBOUNDStpe =>
TypeBounds(readTypeRef(), readTypeRef())
case REFINEDtpe =>
val clazz = readSymbolRef()
RefinedType(until(end, readTypeRef), symScope(clazz), clazz)
case CLASSINFOtpe =>
val clazz = readSymbolRef()
ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
case METHODtpe | IMPLICITMETHODtpe =>
val restpe = readTypeRef()
val params = until(end, readSymbolRef)
// if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType.
// Only happen for trees, "case Apply" in readTree() takes care of selecting the correct
// alternative after parsing the arguments.
if (params.contains(NoSymbol) || restpe == NoType) NoType
else MethodType(params, restpe)
case POLYtpe =>
val restpe = readTypeRef()
val typeParams = until(end, readSymbolRef)
PolyType(typeParams, restpe)
case EXISTENTIALtpe =>
val restpe = readTypeRef()
ExistentialType(until(end, readSymbolRef), restpe)
case ANNOTATEDtpe =>
var typeRef = readNat()
val selfsym = if (isSymbolRef(typeRef)) {
val s = at(typeRef, readSymbol)
typeRef = readNat()
s
} else NoSymbol // selfsym can go.
val tp = at(typeRef, readType)
val annots = until(end, readAnnotationRef)
if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym)
else tp
case _ =>
noSuchTypeTag(tag, end)
}
}
def noSuchTypeTag(tag: Int, end: Int): Type =
errorBadSignature("bad type tag: " + tag)
/** Read a constant */
protected def readConstant(): 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(Float.intBitsToFloat(readLong(len).toInt))
case LITERALdouble => Constant(Double.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): Constant =
errorBadSignature("bad constant tag: " + tag)
/** Read children and store them into the corresponding symbol.
*/
protected def readChildren() {
val tag = readByte()
assert(tag == CHILDREN)
val end = readNat() + readIndex
val target = readSymbolRef()
while (readIndex != end) target addChild readSymbolRef()
}
/** Read an annotation argument, which is pickled either
* as a Constant or a Tree.
*/
protected def readAnnotArg(i: Int): Tree = {
if (bytes(index(i)) == TREE) {
at(i, readTree)
} else {
val const = at(i, readConstant)
global.Literal(const).setType(const.tpe)
}
}
/** Read a ClassfileAnnotArg (argument to a classfile annotation)
*/
protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match {
case ANNOTINFO =>
NestedAnnotArg(at(i, readAnnotation))
case ANNOTARGARRAY =>
at(i, () => {
readByte() // skip the `annotargarray` tag
val end = readNat() + readIndex
ArrayAnnotArg(until(end, () => readClassfileAnnotArg(readNat())).toArray(classfileAnnotArgManifest))
})
case _ =>
LiteralAnnotArg(at(i, readConstant))
}
/** Read an AnnotationInfo. Not to be called directly, use
* readAnnotation or readSymbolAnnotation
*/
protected def readAnnotationInfo(end: Int): AnnotationInfo = {
val atp = readTypeRef()
val args = new ListBuffer[Tree]
val assocs = new ListBuffer[(Name, ClassfileAnnotArg)]
while (readIndex != end) {
val argref = readNat()
if (isNameEntry(argref)) {
val name = at(argref, readName)
val arg = readClassfileAnnotArg(readNat())
assocs += ((name, arg))
}
else
args += readAnnotArg(argref)
}
AnnotationInfo(atp, args.toList, assocs.toList)
}
/** 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() {
val tag = readByte()
if (tag != SYMANNOT)
errorBadSignature("symbol annotation expected ("+ tag +")")
val end = readNat() + readIndex
val target = readSymbolRef()
target.addAnnotation(readAnnotationInfo(end))
}
/** Read an annotation and return it. Used when unpickling
* an ANNOTATED(WSELF)tpe or a NestedAnnotArg */
protected def readAnnotation(): AnnotationInfo = {
val tag = readByte()
if (tag != ANNOTINFO)
errorBadSignature("annotation expected (" + tag + ")")
val end = readNat() + readIndex
readAnnotationInfo(end)
}
/* Read an abstract syntax tree */
protected def readTree(): 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 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() {
symbol = readSymbolRef()
mods = readModifiersRef()
name = readNameRef()
}
/** Read a Symbol and a Name */
def setSymName() {
symbol = readSymbolRef()
name = readNameRef()
}
/** Read a Symbol */
def setSym() {
symbol = readSymbolRef()
}
val t = tag match {
case EMPTYtree =>
EmptyTree
case PACKAGEtree =>
setSym()
// val discardedSymbol = readSymbolRef() // XXX is symbol intentionally not set?
val pid = readTreeRef().asInstanceOf[RefTree]
val stats = until(end, readTreeRef)
PackageDef(pid, stats)
case CLASStree =>
setSymModsName()
val impl = readTemplateRef()
val tparams = until(end, readTypeDefRef)
ClassDef(mods, name, tparams, impl)
case MODULEtree =>
setSymModsName()
ModuleDef(mods, name, readTemplateRef())
case VALDEFtree =>
setSymModsName()
val tpt = readTreeRef()
val rhs = readTreeRef()
ValDef(mods, name, tpt, rhs)
case DEFDEFtree =>
setSymModsName()
val tparams = times(readNat(), readTypeDefRef)
val vparamss = times(readNat(), () => times(readNat(), readValDefRef))
val tpt = readTreeRef()
val rhs = readTreeRef()
DefDef(mods, name, tparams, vparamss, tpt, rhs)
case TYPEDEFtree =>
setSymModsName()
val rhs = readTreeRef()
val tparams = until(end, readTypeDefRef)
TypeDef(mods, name, tparams, rhs)
case LABELtree =>
setSymName()
val rhs = readTreeRef()
val params = until(end, readIdentRef)
LabelDef(name, params, rhs)
case IMPORTtree =>
setSym()
val expr = readTreeRef()
val selectors = until(end, () => {
val from = readNameRef()
val to = readNameRef()
ImportSelector(from, -1, to, -1)
})
Import(expr, selectors)
case TEMPLATEtree =>
setSym()
val parents = times(readNat(), readTreeRef)
val self = readValDefRef()
val body = until(end, readTreeRef)
Template(parents, self, body)
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 =>
Star(readTreeRef())
case BINDtree =>
setSymName()
Bind(name, readTreeRef())
case UNAPPLYtree =>
val fun = readTreeRef()
val args = until(end, readTreeRef)
UnApply(fun, args)
case ARRAYVALUEtree =>
val elemtpt = readTreeRef()
val trees = until(end, readTreeRef)
ArrayValue(elemtpt, trees)
case FUNCTIONtree =>
setSym()
val body = readTreeRef()
val vparams = until(end, readValDefRef)
Function(vparams, body)
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())
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())
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)
case APPLYDYNAMICtree =>
setSym()
val qual = readTreeRef()
val args = until(end, readTreeRef)
ApplyDynamic(qual, args)
case SUPERtree =>
setSym()
val qual = readNameRef()
val mix = readNameRef()
Super(qual, mix)
case THIStree =>
setSym()
This(readNameRef())
case SELECTtree =>
setSym()
val qualifier = readTreeRef()
val selector = readNameRef()
Select(qualifier, selector)
case IDENTtree =>
setSymName()
Ident(name)
case LITERALtree =>
global.Literal(readConstantRef())
case TYPEtree =>
TypeTree()
case ANNOTATEDtree =>
val annot = readTreeRef()
val arg = readTreeRef()
Annotated(annot, arg)
case SINGLETONTYPEtree =>
SingletonTypeTree(readTreeRef())
case SELECTFROMTYPEtree =>
val qualifier = readTreeRef()
val selector = readNameRef()
SelectFromTypeTree(qualifier, selector)
case COMPOUNDTYPEtree =>
CompoundTypeTree(readTemplateRef())
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)
ExistentialTypeTree(tpt, whereClauses)
case _ =>
noSuchTreeTag(tag, end)
}
if (symbol == null) t setType tpe
else t setSymbol symbol setType tpe
}
def noSuchTreeTag(tag: Int, end: Int) =
errorBadSignature("unknown tree type (" + tag + ")")
def readModifiers(): 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 = pickledToRawFlags(pflags)
val privateWithin = readNameRef()
Modifiers(flags, privateWithin, Nil, Map.empty)
}
/* Read a reference to a pickled item */
protected def readNameRef(): Name = at(readNat(), readName)
protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
protected def readTypeRef(): Type = at(readNat(), readType)
protected def readConstantRef(): Constant = at(readNat(), readConstant)
protected def readAnnotationRef(): AnnotationInfo =
at(readNat(), readAnnotation)
protected def readModifiersRef(): Modifiers =
at(readNat(), readModifiers)
protected def readTreeRef(): Tree =
at(readNat(), readTree)
protected def readTemplateRef(): Template =
readTreeRef() match {
case templ:Template => templ
case other =>
errorBadSignature("expected a template (" + other + ")")
}
protected def readCaseDefRef(): CaseDef =
readTreeRef() match {
case tree:CaseDef => tree
case other =>
errorBadSignature("expected a case def (" + other + ")")
}
protected def readValDefRef(): ValDef =
readTreeRef() match {
case tree:ValDef => tree
case other =>
errorBadSignature("expected a ValDef (" + other + ")")
}
protected def readIdentRef(): Ident =
readTreeRef() match {
case tree:Ident => tree
case other =>
errorBadSignature("expected an Ident (" + other + ")")
}
protected def readTypeDefRef(): TypeDef =
readTreeRef() match {
case tree:TypeDef => tree
case other =>
errorBadSignature("expected an TypeDef (" + other + ")")
}
protected def errorBadSignature(msg: String) =
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
protected def errorMissingRequirement(msg: String): Nothing =
if (debug) errorBadSignature(msg)
else throw new IOException("class file needed by "+classRoot.name+" is missing.\n"+msg)
protected def errorMissingRequirement(name: Name, owner: Symbol): Nothing =
errorMissingRequirement("reference " + NameTransformer.decode(name.toString) + " of " + owner.tpe + " refers to nonexisting symbol.")
/** pre: `fun` points to a symbol with an overloaded type.
* Selects the overloaded alternative of `fun` which best matches given
* argument types `argtpes` and result type `restpe`. Stores this alternative as
* the symbol of `fun`.
*/
def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type)
/** Create a lazy type which when completed returns type at index `i`. */
def newLazyTypeRef(i: Int): LazyType
/** Create a lazy type which when completed returns type at index `i` and sets alias
* of completed symbol to symbol at index `j`
*/
def newLazyTypeRefAndAlias(i: Int, j: Int): LazyType
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy