From 36dbbfaa3a01ab9bc8f1f52132aa6524410013c8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Apr 2015 20:56:46 +0200 Subject: Rename Unpickler -> Scala2Unpickler --- .../tools/dotc/core/pickling/ClassfileParser.scala | 4 +- .../tools/dotc/core/pickling/Scala2Unpickler.scala | 1216 ++++++++++++++++++++ src/dotty/tools/dotc/core/pickling/UnPickler.scala | 1216 -------------------- 3 files changed, 1218 insertions(+), 1218 deletions(-) create mode 100644 src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala delete mode 100644 src/dotty/tools/dotc/core/pickling/UnPickler.scala (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 21c9aa84d..480fd968a 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -4,7 +4,7 @@ package core package pickling import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ -import SymDenotations._, UnPickler._, Constants._, Annotations._, util.Positions._ +import SymDenotations._, Scala2Unpickler._, Constants._, Annotations._, util.Positions._ import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString @@ -665,7 +665,7 @@ class ClassfileParser( } def unpickleScala(bytes: Array[Byte]): Boolean = { - new UnPickler(bytes, classRoot, moduleRoot)(ctx).run() + new Scala2Unpickler(bytes, classRoot, moduleRoot)(ctx).run() true } diff --git a/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala new file mode 100644 index 000000000..60fe28229 --- /dev/null +++ b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala @@ -0,0 +1,1216 @@ +package dotty.tools +package dotc +package core +package pickling + +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 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 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[Symbol], 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 some native Dotty idiom. + * @param denot The denotation that gets the converted type as info. + * If `denot` is not an abstract type, this simply returns an equivalent `PolyType`. + * If `denot` is an abstract type, it converts a + * + * TempPolyType(List(v_1 T_1, ..., v_n T_n), lo .. hi) + * + * to a type lambda using `parameterizeWith/LambdaAbstract`. + */ + def depoly(tp: Type, denot: SymDenotation)(implicit ctx: Context): Type = tp match { + case TempPolyType(tparams, restpe) => + if (denot.isAbstractType) + restpe.LambdaAbstract(tparams) // bounds needed? + else if (denot.isAliasType) { + var err: Option[(String, Position)] = None + val result = restpe.parameterizeWith(tparams) + for ((msg, pos) <- err) + ctx.warning( + sm"""$msg + |originally parsed type : ${tp.show} + |will be approximated by: ${result.show}. + |Proceed at own risk.""") + result + } + else + PolyType.fromSymbols(tparams, restpe) + case tp => tp + } + + def addConstructorTypeParams(denot: SymDenotation)(implicit ctx: Context) = { + assert(denot.isConstructor) + denot.info = PolyType.fromSymbols(denot.owner.typeParams, denot.info) + } + + /** 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(paramNames) => + tp.derivedPolyType(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) + } + var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls) + if (parentRefs.isEmpty) parentRefs = defn.ObjectClass.typeRef :: Nil + for (tparam <- tparams) { + val tsym = decls.lookup(tparam.name) + if (tsym.exists) tsym.setFlag(TypeParam) + else denot.enter(tparam, decls) + } + val ost = + if ((selfInfo eq NoType) && (denot is ModuleClass)) + denot.owner.thisType select denot.sourceModule + else selfInfo + if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls) + + val scalacCompanion = denot.classSymbol.scalacLinkedClass + + def registerCompanionPair(module: Symbol, claz: Symbol) = { + val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, module) + if (companionClassMethod.exists) + companionClassMethod.entered + val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, module, claz) + if (companionModuleMethod.exists) + companionModuleMethod.entered + } + + if (denot.flagsUNSAFE is Module) { + registerCompanionPair(denot.classSymbol, scalacCompanion) + } else { + registerCompanionPair(scalacCompanion, denot.classSymbol) + } + + denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost) + } +} + +/** 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) { + + 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( + sm"""error reading Scala signature of $classRoot from $source: + |error occured at position $readIndex: $msg""") + /*if (debug)*/ original.getOrElse(ex).printStackTrace() // !!! DEBUG + throw ex + } + + protected def handleRuntimeException(ex: RuntimeException)(implicit ctx: Context) = ex match { + case ex: BadSignature => throw ex + case _ => errorBadSignature(s"a runtime exception occured: $ex", Some(ex)) + } + + private var postReadOp: Context => Unit = null + + 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) + entries(i) = readSymbol() + if (postReadOp != null) { + postReadOp(ctx) + postReadOp = null + } + 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 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) { + 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 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. + 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.IMPLCLASS_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 = { + 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 => + val infoRef = readNat() + postReadOp = implicit ctx => atReadPos(index(infoRef), readTypeParams) // force reading type params early, so they get entered in the right order. + if (isClassRoot) + completeRoot( + classRoot, rootClassUnpickler(start, classRoot.symbol, NoSymbol)) + else if (isModuleClassRoot) + completeRoot( + moduleClassRoot, rootClassUnpickler(start, moduleClassRoot.symbol, moduleClassRoot.sourceModule)) + 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 LocalUnpickler() 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 MODULEsym | VALsym => + 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) = { + 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) + denot setFlag Scala2x + case denot => + val tp1 = depoly(tp, denot) + 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 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)) + } catch { + case ex: RuntimeException => handleRuntimeException(ex) + } + } + + object localMemberUnpickler extends LocalUnpickler + + def rootClassUnpickler(start: Coord, cls: Symbol, module: Symbol) = + (new LocalUnpickler 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 = { + 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) => + val parent1 = elim(tp.parent) + tp.refinedInfo match { + case TypeAlias(info: TypeRef) if boundSyms contains info.symbol => + RefinedType(parent1, name, info.symbol.info) + case info: TypeRef if boundSyms contains info.symbol => + 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 @ TypeRef(pre, tpnme.Apply) if pre.isLambda => + elim(pre) + case _ => + tp + } + val tp1 = elim(tp) + val isBound = (tp: Type) => boundSyms contains tp.typeSymbol + if (tp1 existsPart isBound) { + 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 (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 tycon.appliedTo(args) + 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 addRefinement(tp: Type, sym: Symbol) = { + def subst(info: Type, rt: RefinedType) = + if (clazz.isClass) info.substThis(clazz.asClass, SkolemType(rt)) + else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case. + RefinedType(tp, sym.name, subst(sym.info, _)) + } + (parent /: decls.toList)(addRefinement).asInstanceOf[RefinedType] + } + 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, restpe.widenExpr) + else ExprType(restpe) + case EXISTENTIALtpe => + val restpe = readTypeRef() + val boundSyms = until(end, readSymbolRef) + elimExistentials(boundSyms, restpe) + case ANNOTATEDtpe => + val tp = readTypeRef() + // no annotation self type is supported, so no test whether this is a symbol ref + val annots = until(end, readAnnotationRef) + AnnotatedType.make(annots, tp) + 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( + defn.SeqType.appliedTo(defn.AnnotationClass.typeRef :: Nil), + until(end, () => readClassfileAnnotArg(readNat()))) + } + + 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 comleted 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 ctx => atReadPos(start, () => readAnnotationContents(end))) + } + + /* 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.Pair(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(defn.SeqType.appliedTo(elemtpt.tpe :: Nil), trees) + // 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(annot, arg) + + case SINGLETONTYPEtree => + SingletonTypeTree(readTreeRef()) + + case SELECTFROMTYPEtree => + val qualifier = readTreeRef() + val selector = readTypeNameRef() + SelectFromTypeTree(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 + Trees.Modifiers[Type](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 + ")") + } + +} diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala deleted file mode 100644 index 3c3ec4a70..000000000 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ /dev/null @@ -1,1216 +0,0 @@ -package dotty.tools -package dotc -package core -package pickling - -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 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 scala.collection.{ mutable, immutable } -import scala.collection.mutable.ListBuffer -import scala.annotation.switch - -object UnPickler { - - /** Exception thrown if classfile is corrupted */ - class BadSignature(msg: String) extends RuntimeException(msg) - - case class TempPolyType(tparams: List[Symbol], 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 some native Dotty idiom. - * @param denot The denotation that gets the converted type as info. - * If `denot` is not an abstract type, this simply returns an equivalent `PolyType`. - * If `denot` is an abstract type, it converts a - * - * TempPolyType(List(v_1 T_1, ..., v_n T_n), lo .. hi) - * - * to a type lambda using `parameterizeWith/LambdaAbstract`. - */ - def depoly(tp: Type, denot: SymDenotation)(implicit ctx: Context): Type = tp match { - case TempPolyType(tparams, restpe) => - if (denot.isAbstractType) - restpe.LambdaAbstract(tparams) // bounds needed? - else if (denot.isAliasType) { - var err: Option[(String, Position)] = None - val result = restpe.parameterizeWith(tparams) - for ((msg, pos) <- err) - ctx.warning( - sm"""$msg - |originally parsed type : ${tp.show} - |will be approximated by: ${result.show}. - |Proceed at own risk.""") - result - } - else - PolyType.fromSymbols(tparams, restpe) - case tp => tp - } - - def addConstructorTypeParams(denot: SymDenotation)(implicit ctx: Context) = { - assert(denot.isConstructor) - denot.info = PolyType.fromSymbols(denot.owner.typeParams, denot.info) - } - - /** 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(paramNames) => - tp.derivedPolyType(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) - } - var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls) - if (parentRefs.isEmpty) parentRefs = defn.ObjectClass.typeRef :: Nil - for (tparam <- tparams) { - val tsym = decls.lookup(tparam.name) - if (tsym.exists) tsym.setFlag(TypeParam) - else denot.enter(tparam, decls) - } - val ost = - if ((selfInfo eq NoType) && (denot is ModuleClass)) - denot.owner.thisType select denot.sourceModule - else selfInfo - if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls) - - val scalacCompanion = denot.classSymbol.scalacLinkedClass - - def registerCompanionPair(module: Symbol, claz: Symbol) = { - val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, module) - if (companionClassMethod.exists) - companionClassMethod.entered - val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, module, claz) - if (companionModuleMethod.exists) - companionModuleMethod.entered - } - - if (denot.flagsUNSAFE is Module) { - registerCompanionPair(denot.classSymbol, scalacCompanion) - } else { - registerCompanionPair(scalacCompanion, denot.classSymbol) - } - - denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost) - } -} - -/** 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 UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(ictx: Context) - extends PickleBuffer(bytes, 0, -1) { - - def showPickled() = { - atReadPos(0, () => { - println(s"classRoot = ${classRoot.debugString}, moduleClassRoot = ${moduleClassRoot.debugString}") - util.ShowPickled.printFile(this) - }) - } - - // print("unpickling "); showPickled() // !!! DEBUG - - import UnPickler._ - - 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( - sm"""error reading Scala signature of $classRoot from $source: - |error occured at position $readIndex: $msg""") - /*if (debug)*/ original.getOrElse(ex).printStackTrace() // !!! DEBUG - throw ex - } - - protected def handleRuntimeException(ex: RuntimeException)(implicit ctx: Context) = ex match { - case ex: BadSignature => throw ex - case _ => errorBadSignature(s"a runtime exception occured: $ex", Some(ex)) - } - - private var postReadOp: Context => Unit = null - - 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) - entries(i) = readSymbol() - if (postReadOp != null) { - postReadOp(ctx) - postReadOp = null - } - 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 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) { - 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 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. - 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.IMPLCLASS_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 = { - 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 => - val infoRef = readNat() - postReadOp = implicit ctx => atReadPos(index(infoRef), readTypeParams) // force reading type params early, so they get entered in the right order. - if (isClassRoot) - completeRoot( - classRoot, rootClassUnpickler(start, classRoot.symbol, NoSymbol)) - else if (isModuleClassRoot) - completeRoot( - moduleClassRoot, rootClassUnpickler(start, moduleClassRoot.symbol, moduleClassRoot.sourceModule)) - 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 LocalUnpickler() 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 MODULEsym | VALsym => - 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) = { - 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) - denot setFlag Scala2x - case denot => - val tp1 = depoly(tp, denot) - 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 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)) - } catch { - case ex: RuntimeException => handleRuntimeException(ex) - } - } - - object localMemberUnpickler extends LocalUnpickler - - def rootClassUnpickler(start: Coord, cls: Symbol, module: Symbol) = - (new LocalUnpickler 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 = { - 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) => - val parent1 = elim(tp.parent) - tp.refinedInfo match { - case TypeAlias(info: TypeRef) if boundSyms contains info.symbol => - RefinedType(parent1, name, info.symbol.info) - case info: TypeRef if boundSyms contains info.symbol => - 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 @ TypeRef(pre, tpnme.Apply) if pre.isLambda => - elim(pre) - case _ => - tp - } - val tp1 = elim(tp) - val isBound = (tp: Type) => boundSyms contains tp.typeSymbol - if (tp1 existsPart isBound) { - 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 (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 tycon.appliedTo(args) - 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 addRefinement(tp: Type, sym: Symbol) = { - def subst(info: Type, rt: RefinedType) = - if (clazz.isClass) info.substThis(clazz.asClass, SkolemType(rt)) - else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case. - RefinedType(tp, sym.name, subst(sym.info, _)) - } - (parent /: decls.toList)(addRefinement).asInstanceOf[RefinedType] - } - 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, restpe.widenExpr) - else ExprType(restpe) - case EXISTENTIALtpe => - val restpe = readTypeRef() - val boundSyms = until(end, readSymbolRef) - elimExistentials(boundSyms, restpe) - case ANNOTATEDtpe => - val tp = readTypeRef() - // no annotation self type is supported, so no test whether this is a symbol ref - val annots = until(end, readAnnotationRef) - AnnotatedType.make(annots, tp) - 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( - defn.SeqType.appliedTo(defn.AnnotationClass.typeRef :: Nil), - until(end, () => readClassfileAnnotArg(readNat()))) - } - - 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 comleted 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 ctx => atReadPos(start, () => readAnnotationContents(end))) - } - - /* 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.Pair(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(defn.SeqType.appliedTo(elemtpt.tpe :: Nil), trees) - // 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(annot, arg) - - case SINGLETONTYPEtree => - SingletonTypeTree(readTreeRef()) - - case SELECTFROMTYPEtree => - val qualifier = readTreeRef() - val selector = readTypeNameRef() - SelectFromTypeTree(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 - Trees.Modifiers[Type](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 + ")") - } - -} -- cgit v1.2.3 From dad799912e80377310d6f2408a78344dc2112d8b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Apr 2015 21:03:09 +0200 Subject: ClassfileParser and SymbolLoader should return embedded unpicklers To be able able to post process pickled TASTY tree we let ClassfileParser#run return any embedded unpickler. The unpickler is further propagated by a new method ClassFileLoader#load in SymbolLoaders. --- src/dotty/tools/dotc/core/SymbolLoaders.scala | 5 +- .../tools/dotc/core/pickling/ClassfileParser.scala | 72 ++++++++++++---------- .../tools/dotc/core/pickling/DottyUnpickler.scala | 2 +- .../tools/dotc/core/pickling/Scala2Unpickler.scala | 2 +- 4 files changed, 46 insertions(+), 35 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index 0e8c9a41d..296c4ad1e 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -251,7 +251,10 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { else (rootDenot, linkedDenot) } - def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { + override def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = + load(root) + + def load(root: SymDenotation)(implicit ctx: Context): Option[ClassfileParser.Embedded] = { val (classRoot, moduleRoot) = rootDenots(root.asClass) new ClassfileParser(classfile, classRoot, moduleRoot)(ctx).run() } diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 480fd968a..918a97476 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -15,12 +15,18 @@ import typer.Checking.checkNonCyclic import io.AbstractFile import scala.util.control.NonFatal +object ClassfileParser { + /** Marker trait for unpicklers that can be embedded in classfiles. */ + trait Embedded +} + class ClassfileParser( classfile: AbstractFile, classRoot: ClassDenotation, moduleRoot: ClassDenotation)(ictx: Context) { import ClassfileConstants._ + import ClassfileParser._ protected val in = new AbstractFileReader(classfile) @@ -41,7 +47,7 @@ class ClassfileParser( private def mismatchError(c: Symbol) = throw new IOException(s"class file '${in.file}' has location not matching its contents: contains $c") - def run()(implicit ctx: Context): Unit = try { + def run()(implicit ctx: Context): Option[Embedded] = try { ctx.debuglog("[class] >> " + classRoot.fullName) parseHeader this.pool = new ConstantPool @@ -80,7 +86,7 @@ class ClassfileParser( var sawPrivateConstructor = false - def parseClass()(implicit ctx: Context): Unit = { + def parseClass()(implicit ctx: Context): Option[Embedded] = { val jflags = in.nextChar val isAnnotation = hasAnnotation(jflags) val sflags = FlagTranslation.classFlags(jflags) @@ -94,8 +100,6 @@ class ClassfileParser( addEnclosingTParams() - if (unpickleOrParseInnerClasses()) return - /** Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled. * Updates the read pointer of 'in'. */ def parseParents: List[Type] = { @@ -114,33 +118,36 @@ class ClassfileParser( superType :: ifaces } - var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) + val result = unpickleOrParseInnerClasses() + if (!result.isDefined) { + var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) // might be reassigned by later parseAttributes - val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol) + val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol) - enterOwnInnerClasses + enterOwnInnerClasses - classRoot.setFlag(sflags) - moduleRoot.setFlag(Flags.JavaDefined | Flags.ModuleClassCreationFlags) - setPrivateWithin(classRoot, jflags) - setPrivateWithin(moduleRoot, jflags) - setPrivateWithin(moduleRoot.sourceModule, jflags) + classRoot.setFlag(sflags) + moduleRoot.setFlag(Flags.JavaDefined | Flags.ModuleClassCreationFlags) + setPrivateWithin(classRoot, jflags) + setPrivateWithin(moduleRoot, jflags) + setPrivateWithin(moduleRoot.sourceModule, jflags) - for (i <- 0 until in.nextChar) parseMember(method = false) - for (i <- 0 until in.nextChar) parseMember(method = true) - classInfo = parseAttributes(classRoot.symbol, classInfo) - if (isAnnotation) addAnnotationConstructor(classInfo) + for (i <- 0 until in.nextChar) parseMember(method = false) + for (i <- 0 until in.nextChar) parseMember(method = true) + classInfo = parseAttributes(classRoot.symbol, classInfo) + if (isAnnotation) addAnnotationConstructor(classInfo) - val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot) - if (companionClassMethod.exists) companionClassMethod.entered - val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot) - if (companionModuleMethod.exists) companionModuleMethod.entered + val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot) + if (companionClassMethod.exists) companionClassMethod.entered + val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot) + if (companionModuleMethod.exists) companionModuleMethod.entered - setClassInfo(classRoot, classInfo) - setClassInfo(moduleRoot, staticInfo) + setClassInfo(classRoot, classInfo) + setClassInfo(moduleRoot, staticInfo) + } + result } - /** Add type parameters of enclosing classes */ def addEnclosingTParams()(implicit ctx: Context): Unit = { var sym = classRoot.owner @@ -644,7 +651,7 @@ class ClassfileParser( * Restores the old `bp`. * @return true iff classfile is from Scala, so no Java info needs to be read. */ - def unpickleOrParseInnerClasses()(implicit ctx: Context): Boolean = { + def unpickleOrParseInnerClasses()(implicit ctx: Context): Option[Embedded] = { val oldbp = in.bp try { skipSuperclasses() @@ -664,15 +671,16 @@ class ClassfileParser( i < attrs } - def unpickleScala(bytes: Array[Byte]): Boolean = { - new Scala2Unpickler(bytes, classRoot, moduleRoot)(ctx).run() - true + def unpickleScala(bytes: Array[Byte]): Some[Embedded] = { + val unpickler = new Scala2Unpickler(bytes, classRoot, moduleRoot)(ctx) + unpickler.run() + Some(unpickler) } - def unpickleTASTY(bytes: Array[Byte]): Boolean = { - new DottyUnpickler(bytes) - .enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule)) - true + def unpickleTASTY(bytes: Array[Byte]): Some[Embedded] = { + val unpickler = new DottyUnpickler(bytes) + unpickler.enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule)) + Some(unpickler) } def parseScalaSigBytes: Array[Byte] = { @@ -739,7 +747,7 @@ class ClassfileParser( } } } - false + None } finally in.bp = oldbp } diff --git a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala index 64be68975..6e7bd9210 100644 --- a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala @@ -18,7 +18,7 @@ object DottyUnpickler { /** A class for unpickling Tasty trees and symbols. * @param bytes the bytearray containing the Tasty file from which we unpickle */ -class DottyUnpickler(bytes: Array[Byte]) { +class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded { import tpd._ private val unpickler = new TastyUnpickler(bytes) diff --git a/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala index 60fe28229..5fbb4b57f 100644 --- a/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala @@ -148,7 +148,7 @@ object Scala2Unpickler { * @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) { + extends PickleBuffer(bytes, 0, -1) with ClassfileParser.Embedded { def showPickled() = { atReadPos(0, () => { -- cgit v1.2.3 From 12f2ee7042c8f44a81afa54bdf261d4cd2a31b9c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Apr 2015 21:24:55 +0200 Subject: Compiler for embedded TASTY info. `FromTasty` is a main module which compiles TASTY info instead of sources. --- src/dotty/tools/dotc/Compiler.scala | 8 +++- src/dotty/tools/dotc/FromTasty.scala | 90 ++++++++++++++++++++++++++++++++++++ src/dotty/tools/dotc/Run.scala | 30 ++++++------ 3 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 src/dotty/tools/dotc/FromTasty.scala (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 1657adbbb..6787e3a2d 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -8,7 +8,7 @@ import Symbols._ import Scopes._ import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks} import reporting.ConsoleReporter -import dotty.tools.dotc.core.Phases.Phase +import Phases.Phase import dotty.tools.dotc.transform._ import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer} import dotty.tools.dotc.core.DenotTransformers.DenotTransformer @@ -101,9 +101,13 @@ class Compiler { (start.setRunInfo(new RunInfo(start)) /: defn.RootImports)(addImport) } - def newRun(implicit ctx: Context): Run = { + def reset()(implicit ctx: Context): Unit = { ctx.base.reset() ctx.runInfo.clear() + } + + def newRun(implicit ctx: Context): Run = { + reset() new Run(this)(rootContext) } } diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala new file mode 100644 index 000000000..844f5fe76 --- /dev/null +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -0,0 +1,90 @@ +/* dotc + * Copyright 2005-2015 LAMP/EPFL + * @author Martin Odersky + */ +package dotty.tools +package dotc + +import core._ +import Contexts._ +import Symbols._ +import SymDenotations._ +import typer.FrontEnd +import Phases.Phase +import util._ +import Decorators._ +import dotty.tools.dotc.transform.Pickler +import pickling.DottyUnpickler + +object FromTasty extends Driver { + override def newCompiler(): Compiler = new TASTYCompiler + + class TASTYCompiler extends Compiler { + + override def phases: List[List[Phase]] = { + val backendPhases = super.phases.dropWhile { + case List(_: Pickler) => false + case _ => true + }.tail + List(new ReadTastyTreesFromClasses) :: backendPhases + } + + override def newRun(implicit ctx: Context): Run = { + reset() + new TASTYRun(this)(rootContext) + } + } + + class TASTYRun(comp: Compiler)(implicit ctx: Context) extends Run(comp) { + override def compile(classNames: List[String]) = { + units = classNames.map(new TASTYCompilationUnit(_)) + compileUnits() + } + } + + class TASTYCompilationUnit(val className: String) extends CompilationUnit(NoSource) { + override def toString = s"class file $className" + } + + class ReadTastyTreesFromClasses extends FrontEnd { + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = + units.map(readTASTY) + + def readTASTY(unit: CompilationUnit)(implicit ctx: Context): CompilationUnit = unit match { + case unit: TASTYCompilationUnit => + val className = unit.className.toTypeName + val clsd = + if (className.contains('.')) ctx.base.staticRef(className) + else defn.EmptyPackageClass.info.decl(className) + def cannotUnpickle(reason: String) = { + ctx.error(s"class $className cannot be unpickled because $reason") + unit + } + clsd match { + case clsd: ClassDenotation => + clsd.infoOrCompleter match { + case info: ClassfileLoader => + info.load(clsd) match { + case Some(unpickler: DottyUnpickler) => + val (List(unpickled), sources) = unpickler.body(readPositions = false) + val unit1 = sources.get(unpickled) match { + case Some(source) => new CompilationUnit(source) + case _ => unit + } + unit1.tpdTree = unpickled + unit1.embeddedSources = sources - unpickled + unit1 + case _ => + cannotUnpickle(s"it does not have a TASTY attribute") + } + case info => + cannotUnpickle(s"its info of type ${info.getClass} is not a ClassfileLoader") + } + case _ => + println(defn.EmptyPackageClass.info.decls) + ctx.error(s"class not found: $className") + unit + } + } + } +} diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index af9c878f0..a008214c9 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -38,23 +38,25 @@ class Run(comp: Compiler)(implicit ctx: Context) { * or we need to assmeble phases on each run, and take -Yskip, -Ystop into * account. I think the latter would be preferable. */ - def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat { + def compileSources(sources: List[SourceFile]) = if (sources forall (_.exists)) { - val phases = ctx.squashPhases(ctx.phasePlan, - ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) - ctx.usePhases(phases) units = sources map (new CompilationUnit(_)) - for (phase <- ctx.allPhases) - if (!ctx.reporter.hasErrors) { - if (ctx.settings.verbose.value) println(s"[$phase]") - units = phase.runOn(units) - def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = - for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) - if (ctx.settings.Xprint.value.containsPhase(phase)) - foreachUnit(printTree) - - } + compileUnits() } + + protected def compileUnits() = Stats.monitorHeartBeat { + val phases = ctx.squashPhases(ctx.phasePlan, + ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) + ctx.usePhases(phases) + for (phase <- ctx.allPhases) + if (!ctx.reporter.hasErrors) { + if (ctx.settings.verbose.value) println(s"[$phase]") + units = phase.runOn(units) + def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = + for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) + if (ctx.settings.Xprint.value.containsPhase(phase)) + foreachUnit(printTree) + } } private def printTree(ctx: Context) = { -- cgit v1.2.3 From a4d86e9640e33506d9c9cec625567907a82cd16f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Apr 2015 21:49:30 +0200 Subject: Fix definition of empty package so that it can persist members Previously, the empty package was always initialized with the empty scope. This means that separate compilation between files in the empty package was not possible. --- src/dotty/tools/dotc/core/Definitions.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 7de254008..3c36b1a1e 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -4,7 +4,7 @@ package core import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._ import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._ -import pickling.UnPickler.ensureConstructor +import pickling.Scala2Unpickler.ensureConstructor import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import PartialFunction._ @@ -99,7 +99,8 @@ class Definitions { lazy val RootPackage: TermSymbol = ctx.newSymbol( NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass)) - lazy val EmptyPackageVal = ctx.newCompletePackageSymbol(RootClass, nme.EMPTY_PACKAGE).entered + lazy val EmptyPackageVal = ctx.newPackageSymbol( + RootClass, nme.EMPTY_PACKAGE, (emptypkg, emptycls) => ctx.rootLoader(emptypkg)).entered lazy val EmptyPackageClass = EmptyPackageVal.moduleClass.asClass /** A package in which we can place all methods that are interpreted specially by the compiler */ -- cgit v1.2.3 From 512689c11348144023e7b55298cc5d9be3203eb0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Apr 2015 09:50:44 +0200 Subject: Unpickler should not label parameter accessors Deferred. --- src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala index ba3023ed1..25fecbbbf 100644 --- a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala @@ -338,7 +338,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || isAbstractType var flags = givenFlags - if (lacksDefinition) flags |= Deferred + if (lacksDefinition && tag != PARAM) flags |= Deferred if (tag == DEFDEF) flags |= Method if (givenFlags is Module) flags = flags | (if (tag == VALDEF) ModuleCreationFlags else ModuleClassCreationFlags) -- cgit v1.2.3 From 014ad9bc44ae8abaac5ec40c8993f09fa289eff3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Apr 2015 10:23:03 +0200 Subject: Maintain source files in pickled info So far: Only one source file is recorded. Should evaluate whether more are needed. Will programs composed from several source files be pickled? They will certainly be generated after inlining, but maybe all that happens after pickling? --- src/dotty/tools/dotc/CompilationUnit.scala | 6 +++--- src/dotty/tools/dotc/FromTasty.scala | 8 ++------ src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala | 15 +++++++++++---- src/dotty/tools/dotc/core/pickling/PickleFormat.scala | 2 ++ src/dotty/tools/dotc/transform/Pickler.scala | 17 +++++++++++++---- 5 files changed, 31 insertions(+), 17 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/CompilationUnit.scala b/src/dotty/tools/dotc/CompilationUnit.scala index 4f8c30aab..f0ce19320 100644 --- a/src/dotty/tools/dotc/CompilationUnit.scala +++ b/src/dotty/tools/dotc/CompilationUnit.scala @@ -25,14 +25,14 @@ class CompilationUnit(val source: SourceFile) { */ var picklers: Map[ClassSymbol, TastyPickler] = Map() - /** + /** TODO: I'd prefer we do not put this in CompilationUnit * Addresses in TASTY file of trees, stored by pickling. * Note that trees are checked for reference equality, - * so one can reliably use this function only dirrectly after `pickler` + * so one can reliably use this function only directly after `pickler` */ var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) - /** + /** TODO: I'd prefer we do not put this in CompilationUnit * Addresses in TASTY file of symbols, stored by pickling. * Note that trees are checked for reference equality, * so one can reliably use this function only dirrectly after `pickler` diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala index 844f5fe76..2c704efc2 100644 --- a/src/dotty/tools/dotc/FromTasty.scala +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -66,13 +66,9 @@ object FromTasty extends Driver { case info: ClassfileLoader => info.load(clsd) match { case Some(unpickler: DottyUnpickler) => - val (List(unpickled), sources) = unpickler.body(readPositions = false) - val unit1 = sources.get(unpickled) match { - case Some(source) => new CompilationUnit(source) - case _ => unit - } + val (List(unpickled), source) = unpickler.body(readPositions = false) + val unit1 = new CompilationUnit(source) unit1.tpdTree = unpickled - unit1.embeddedSources = sources - unpickled unit1 case _ => cannotUnpickle(s"it does not have a TASTY attribute") diff --git a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala index 6e7bd9210..2d8f571ec 100644 --- a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala @@ -7,6 +7,7 @@ import Contexts._, SymDenotations._ import dotty.tools.dotc.ast.tpd import TastyUnpickler._, TastyBuffer._ import util.Positions._ +import util.{SourceFile, NoSource} import PositionUnpickler._ object DottyUnpickler { @@ -30,14 +31,20 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded { def enter(roots: Set[SymDenotation])(implicit ctx: Context): Unit = treeUnpickler.enterTopLevel(roots) - /** The unpickled trees + /** The unpickled trees, and the source file they come from * @param readPositions if true, trees get decorated with position information. */ - def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = { + def body(readPositions: Boolean = false)(implicit ctx: Context): (List[Tree], SourceFile) = { + val source = unpickler.unpickle(new SourceFileUnpickler).getOrElse(NoSource) if (readPositions) - for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler())) + for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler)) treeUnpickler.usePositions(totalRange, positions) - treeUnpickler.unpickle() + (treeUnpickler.unpickle(), source) + } + + private class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + new SourceFile(tastyName(reader.readNameRef()).toString, Seq()) } private class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") { diff --git a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala index d12a879ba..4f3841212 100644 --- a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala +++ b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala @@ -185,6 +185,8 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t Category 4 (tags 112-127): tag Nat AST Category 5 (tags 128-255): tag Length +Standard Section: "Sourcefile" sourcefile_NameRef + Standard Section: "Positions" sourceLength_Nat Assoc* Assoc = addr_Delta offset_Delta offset_Delta? diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index c09ba6889..d30c876bd 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -11,6 +11,7 @@ import Periods._ import Phases._ import Symbols._ import Flags.Module +import util.SourceFile import collection.mutable /** This phase pickles trees */ @@ -47,6 +48,8 @@ class Pickler extends Phase { treePkl.pickle(tree :: Nil) unit.addrOfTree = treePkl.buf.addrOfTree unit.addrOfSym = treePkl.addrOfSym + if (unit.source.exists) + pickleSourcefile(pickler, unit.source) if (tree.pos.exists) new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos) @@ -62,6 +65,12 @@ class Pickler extends Phase { } } + private def pickleSourcefile(pickler: TastyPickler, source: SourceFile): Unit = { + val buf = new TastyBuffer(10) + pickler.newSection("Sourcefile", buf) + buf.writeNat(pickler.nameBuffer.nameIndex(source.file.path).index) + } + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { val result = super.runOn(units) if (ctx.settings.YtestPickler.value) @@ -80,16 +89,16 @@ class Pickler extends Phase { } pickling.println("************* entered toplevel ***********") for ((cls, unpickler) <- unpicklers) { - val unpickled = unpickler.body(readPositions = false) - testSame(i"$unpickled%\n%", beforePickling(cls), cls) + val (unpickled, source) = unpickler.body(readPositions = false) + testSame(i"$unpickled%\n%", beforePickling(cls), cls, source) } } - private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) = + private def testSame(unpickled: String, previous: String, cls: ClassSymbol, source: SourceFile)(implicit ctx: Context) = if (previous != unpickled) { output("before-pickling.txt", previous) output("after-pickling.txt", unpickled) - ctx.error(s"""pickling difference for ${cls.fullName}, for details: + ctx.error(s"""pickling difference for ${cls.fullName} in $source, for details: | | diff before-pickling.txt after-pickling.txt""".stripMargin) } -- cgit v1.2.3 From 12d5dbcfa405dbb8ef56f4983d8fd08d33f97438 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Apr 2015 10:55:37 +0200 Subject: Handle missing delta positions when unpickling A missing delta position signifies that the node has the same position as its parent. Once that case was added, we can now enable positions when reading from Tasty. --- src/dotty/tools/dotc/FromTasty.scala | 5 ++--- src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala | 11 ++++++----- src/dotty/tools/dotc/transform/Pickler.scala | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala index 2c704efc2..106c7fc00 100644 --- a/src/dotty/tools/dotc/FromTasty.scala +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -66,18 +66,17 @@ object FromTasty extends Driver { case info: ClassfileLoader => info.load(clsd) match { case Some(unpickler: DottyUnpickler) => - val (List(unpickled), source) = unpickler.body(readPositions = false) + val (List(unpickled), source) = unpickler.body(readPositions = true) val unit1 = new CompilationUnit(source) unit1.tpdTree = unpickled unit1 case _ => - cannotUnpickle(s"it does not have a TASTY attribute") + cannotUnpickle(s"its class file ${info.classfile} does not have a TASTY attribute") } case info => cannotUnpickle(s"its info of type ${info.getClass} is not a ClassfileLoader") } case _ => - println(defn.EmptyPackageClass.info.decls) ctx.error(s"class not found: $className") unit } diff --git a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala index 25fecbbbf..7b143dfad 100644 --- a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala @@ -860,11 +860,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } } - private def setNormalized(tree: Tree, parentPos: Position): Unit = { - assert(tree.pos.exists) - val absPos = Position(parentPos.start + offsetToInt(tree.pos.start), parentPos.end - tree.pos.end) - tree.setPosUnchecked(absPos) - } + private def setNormalized(tree: Tree, parentPos: Position): Unit = + tree.setPosUnchecked( + if (tree.pos.exists) + Position(parentPos.start + offsetToInt(tree.pos.start), parentPos.end - tree.pos.end) + else + parentPos) def normalizePos(x: Any, parentPos: Position)(implicit ctx: Context): Unit = traverse(x, parentPos, setNormalized) diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index d30c876bd..5da92c079 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -89,7 +89,7 @@ class Pickler extends Phase { } pickling.println("************* entered toplevel ***********") for ((cls, unpickler) <- unpicklers) { - val (unpickled, source) = unpickler.body(readPositions = false) + val (unpickled, source) = unpickler.body(readPositions = true) testSame(i"$unpickled%\n%", beforePickling(cls), cls, source) } } -- cgit v1.2.3 From a347632d48390a986c3bb44cf7b3cc2f3f988110 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Apr 2015 12:25:21 +0200 Subject: Add usage documentation to FromTasty --- src/dotty/tools/dotc/FromTasty.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala index 106c7fc00..3d3ae01c1 100644 --- a/src/dotty/tools/dotc/FromTasty.scala +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -16,6 +16,17 @@ import Decorators._ import dotty.tools.dotc.transform.Pickler import pickling.DottyUnpickler +/** Compiler for TASTY files. + * Usage: + * + * scala dotty.tools.dotc.FromTasty (option | classname)* + * + * Options are as for dotc. + * Classnames are fully qualified names of top-level classes that need to have a TASTY attribute. + * Example: + * + * scala dotty.tools.dotc.FromTasty -Xprint:front extMethods.T + */ object FromTasty extends Driver { override def newCompiler(): Compiler = new TASTYCompiler -- cgit v1.2.3 From 9e2dd75a8c229239b59a75fe6f9ddf201946032e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Apr 2015 12:59:34 +0200 Subject: Move addrOfTree, addOfSym from CompilationUnit to Pickler. These only exist if there was a pickler, and they are not unique per CompilationUnit. --- src/dotty/tools/dotc/CompilationUnit.scala | 14 -------------- src/dotty/tools/dotc/core/pickling/TastyPickler.scala | 16 ++++++++++++++++ src/dotty/tools/dotc/transform/Pickler.scala | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/CompilationUnit.scala b/src/dotty/tools/dotc/CompilationUnit.scala index f0ce19320..f5899f0f2 100644 --- a/src/dotty/tools/dotc/CompilationUnit.scala +++ b/src/dotty/tools/dotc/CompilationUnit.scala @@ -24,18 +24,4 @@ class CompilationUnit(val source: SourceFile) { * Subsequent phases can add new sections. */ var picklers: Map[ClassSymbol, TastyPickler] = Map() - - /** TODO: I'd prefer we do not put this in CompilationUnit - * Addresses in TASTY file of trees, stored by pickling. - * Note that trees are checked for reference equality, - * so one can reliably use this function only directly after `pickler` - */ - var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) - - /** TODO: I'd prefer we do not put this in CompilationUnit - * Addresses in TASTY file of symbols, stored by pickling. - * Note that trees are checked for reference equality, - * so one can reliably use this function only dirrectly after `pickler` - */ - var addrOfSym: Symbol => Option[Addr] = (_ => None) } diff --git a/src/dotty/tools/dotc/core/pickling/TastyPickler.scala b/src/dotty/tools/dotc/core/pickling/TastyPickler.scala index 6bd6f1c44..74cc72b8c 100644 --- a/src/dotty/tools/dotc/core/pickling/TastyPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TastyPickler.scala @@ -7,6 +7,8 @@ import PickleFormat._ import collection.mutable import TastyBuffer._ import java.util.UUID +import core.Symbols.Symbol +import ast.tpd class TastyPickler { @@ -51,4 +53,18 @@ class TastyPickler { assert(all.length == totalSize && all.bytes.length == totalSize, s"totalSize = $totalSize, all.length = ${all.length}, all.bytes.length = ${all.bytes.length}") all.bytes } + + /** + * Addresses in TASTY file of trees, stored by pickling. + * Note that trees are checked for reference equality, + * so one can reliably use this function only directly after `pickler` + */ + var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) + + /** + * Addresses in TASTY file of symbols, stored by pickling. + * Note that trees are checked for reference equality, + * so one can reliably use this function only dirrectly after `pickler` + */ + var addrOfSym: Symbol => Option[Addr] = (_ => None) } diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index 5da92c079..50a419589 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -46,8 +46,8 @@ class Pickler extends Phase { unit.picklers += (cls -> pickler) val treePkl = new TreePickler(pickler) treePkl.pickle(tree :: Nil) - unit.addrOfTree = treePkl.buf.addrOfTree - unit.addrOfSym = treePkl.addrOfSym + pickler.addrOfTree = treePkl.buf.addrOfTree + pickler.addrOfSym = treePkl.addrOfSym if (unit.source.exists) pickleSourcefile(pickler, unit.source) if (tree.pos.exists) -- cgit v1.2.3 From 10a5f9198f03ae5b8dc54f1113f98da585c4e81a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Apr 2015 15:52:58 +0200 Subject: Force TASTY trees read by unpickler in FromTasty We want to ensure that the whole tree is read at phase frontend. To achieve this, we run an empty traverser over the tree. --- src/dotty/tools/dotc/FromTasty.scala | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala index 3d3ae01c1..37f6933bf 100644 --- a/src/dotty/tools/dotc/FromTasty.scala +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -15,6 +15,7 @@ import util._ import Decorators._ import dotty.tools.dotc.transform.Pickler import pickling.DottyUnpickler +import ast.tpd._ /** Compiler for TASTY files. * Usage: @@ -57,6 +58,10 @@ object FromTasty extends Driver { override def toString = s"class file $className" } + object force extends TreeTraverser { + def traverse(tree: Tree)(implicit ctx: Context): Unit = traverseChildren(tree) + } + class ReadTastyTreesFromClasses extends FrontEnd { override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = units.map(readTASTY) @@ -80,6 +85,7 @@ object FromTasty extends Driver { val (List(unpickled), source) = unpickler.body(readPositions = true) val unit1 = new CompilationUnit(source) unit1.tpdTree = unpickled + force.traverse(unit1.tpdTree) unit1 case _ => cannotUnpickle(s"its class file ${info.classfile} does not have a TASTY attribute") -- cgit v1.2.3