diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2013-10-16 15:12:12 -0700 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2013-10-16 15:12:12 -0700 |
commit | 1571af7a8a7e78b67d052f371abc44c751930666 (patch) | |
tree | 615d91e3b92b5099d1089a69e81e06f6f905d1c8 /src/compiler | |
parent | ae47ccc35bdcfbdb965e2297b131a2416495d4e7 (diff) | |
parent | 1edddfa7fd3066b2c336eb16f105283f5e9c18cd (diff) | |
download | scala-1571af7a8a7e78b67d052f371abc44c751930666.tar.gz scala-1571af7a8a7e78b67d052f371abc44c751930666.tar.bz2 scala-1571af7a8a7e78b67d052f371abc44c751930666.zip |
Merge pull request #3033 from paulp/pr/pickler-redux
Traverser and Pickler improvements.
Diffstat (limited to 'src/compiler')
4 files changed, 191 insertions, 686 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 9ac1ce1b9c..ce3e7b1bb5 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -11,6 +11,7 @@ import java.lang.Float.floatToIntBits import java.lang.Double.doubleToLongBits import scala.io.Codec import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat } +import scala.reflect.internal.util.shortClassOfInstance import scala.collection.mutable.LinkedHashMap import PickleFormat._ import Flags._ @@ -80,7 +81,7 @@ abstract class Pickler extends SubComponent { private var entries = new Array[AnyRef](256) private var ep = 0 private val index = new LinkedHashMap[AnyRef, Int] - private lazy val nonClassRoot = findOrElse(root.ownersIterator)(!_.isClass)(NoSymbol) + private lazy val nonClassRoot = findSymbol(root.ownersIterator)(!_.isClass) private def isRootSym(sym: Symbol) = sym.name.toTermName == rootName && sym.owner == rootOwner @@ -106,13 +107,14 @@ abstract class Pickler extends SubComponent { * anyway? This is the case if symbol is a refinement class, * an existentially bound variable, or a higher-order type parameter. */ - private def isLocal(sym: Symbol): Boolean = - !sym.isPackageClass && sym != NoSymbol && - (isRootSym(sym) || - sym.isRefinementClass || - sym.isAbstractType && sym.hasFlag(EXISTENTIAL) || // existential param - sym.isParameter || - isLocal(sym.owner)) + private def isLocal(sym: Symbol): Boolean = (sym != NoSymbol) && !sym.isPackageClass && ( + isRootSym(sym) + || sym.isRefinementClass + || sym.isAbstractType && sym.hasFlag(EXISTENTIAL) // existential param + || sym.isParameter + || isLocal(sym.owner) + ) + private def isExternalSymbol(sym: Symbol): Boolean = (sym != NoSymbol) && !isLocal(sym) // Phase 1 methods: Populate entries/index ------------------------------------ @@ -135,13 +137,18 @@ abstract class Pickler extends SubComponent { true } + private def deskolemizeTypeSymbols(ref: AnyRef): AnyRef = ref match { + case sym: Symbol => deskolemize(sym) + case _ => ref + } + /** If the symbol is a type skolem, deskolemize and log it. * If we fail to deskolemize, in a method like * trait Trait[+A] { def f[CC[X]] : CC[A] } * the applied type CC[A] will hold a different CC symbol * than the type-constructor type-parameter CC. */ - private def deskolemize(sym: Symbol) = { + private def deskolemize(sym: Symbol): Symbol = { if (sym.isTypeSkolem) { val sym1 = sym.deSkolemize log({ @@ -169,7 +176,7 @@ abstract class Pickler extends SubComponent { putSymbol(sym.owner) putSymbol(sym.privateWithin) putType(sym.info) - if (sym.thisSym.tpeHK != sym.tpeHK) + if (sym.hasSelfType) putType(sym.typeOfThis) putSymbol(sym.alias) if (!sym.children.isEmpty) { @@ -202,252 +209,65 @@ abstract class Pickler extends SubComponent { case ThisType(sym) => putSymbol(sym) case SingleType(pre, sym) => - putType(pre); putSymbol(sym) + putType(pre) + putSymbol(sym) case SuperType(thistpe, supertpe) => putType(thistpe) putType(supertpe) case ConstantType(value) => putConstant(value) case TypeRef(pre, sym, args) => -// if (sym.isAbstractType && (sym hasFlag EXISTENTIAL)) -// if (!(boundSyms contains sym)) -// println("unbound existential: "+sym+sym.locationString) - putType(pre); putSymbol(sym); putTypes(args) + putType(pre) + putSymbol(sym) + putTypes(args) case TypeBounds(lo, hi) => - putType(lo); putType(hi) - case RefinedType(parents, decls) => - val rclazz = tp.typeSymbol - for (m <- decls.iterator) - if (m.owner != rclazz) abort("bad refinement member "+m+" of "+tp+", owner = "+m.owner) - putSymbol(rclazz); putTypes(parents); putSymbols(decls.toList) - case ClassInfoType(parents, decls, clazz) => - putSymbol(clazz); putTypes(parents); putSymbols(decls.toList) + putType(lo) + putType(hi) + case tp: CompoundType => + putSymbol(tp.typeSymbol) + putTypes(tp.parents) + putSymbols(tp.decls.toList) case MethodType(params, restpe) => - putType(restpe); putSymbols(params) + putType(restpe) + putSymbols(params) case NullaryMethodType(restpe) => putType(restpe) case PolyType(tparams, restpe) => - /* no longer needed since all params are now local - tparams foreach { tparam => - if (!isLocal(tparam)) locals += tparam // similar to existential types, these tparams are local - } - */ - putType(restpe); putSymbols(tparams) + putType(restpe) + putSymbols(tparams) case ExistentialType(tparams, restpe) => -// val savedBoundSyms = boundSyms // boundSyms are known to be local based on the EXISTENTIAL flag (see isLocal) -// boundSyms = tparams ::: boundSyms -// try { - putType(restpe) - // } finally { -// boundSyms = savedBoundSyms -// } + putType(restpe) putSymbols(tparams) - case AnnotatedType(annotations, underlying, selfsym) => + case AnnotatedType(_, underlying, selfsym) => putType(underlying) if (settings.selfInAnnots) putSymbol(selfsym) - putAnnotations(annotations filter (_.isStatic)) + tp.staticAnnotations foreach putAnnotation case _ => throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")") } } private def putTypes(tps: List[Type]) { tps foreach putType } - private def putTree(tree: Tree): Unit = if (putEntry(tree)) { - if (tree != EmptyTree) - putType(tree.tpe) - if (tree.hasSymbolField) - putSymbol(tree.symbol) - - tree match { - case EmptyTree => - - case tree@PackageDef(pid, stats) => - putTree(pid) - putTrees(stats) - - case ClassDef(mods, name, tparams, impl) => - putMods(mods) - putEntry(name) - putTree(impl) - putTrees(tparams) - - case ModuleDef(mods, name, impl) => - putMods(mods) - putEntry(name) - putTree(impl) - - case ValDef(mods, name, tpt, rhs) => - putMods(mods) - putEntry(name) - putTree(tpt) - putTree(rhs) - - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - putMods(mods) - putEntry(name) - putTrees(tparams) - putTreess(vparamss) - putTree(tpt) - putTree(rhs) - - case TypeDef(mods, name, tparams, rhs) => - putMods(mods) - putEntry(name) - putTree(rhs) - putTrees(tparams) - - case LabelDef(name, params, rhs) => - putEntry(name) - putTree(rhs) - putTrees(params) - - case Import(expr, selectors) => - putTree(expr) - for (ImportSelector(from, _, to, _) <- selectors) { - putEntry(from) - putEntry(to) - } -/* - case DocDef(comment, definition) => should not be needed - putConstant(Constant(comment)) - putTree(definition) -*/ - case Template(parents, self, body) => - putTrees(parents) - putTree(self) - putTrees(body) - - case Block(stats, expr) => - putTree(expr) - putTrees(stats) - - case CaseDef(pat, guard, body) => - putTree(pat) - putTree(guard) - putTree(body) - - case Alternative(trees) => - putTrees(trees) - - case Star(elem) => - putTree(elem) - - case Bind(name, body) => - putEntry(name) - putTree(body) - - case UnApply(fun: Tree, args) => - putTree(fun) - putTrees(args) - - case ArrayValue(elemtpt, trees) => - putTree(elemtpt) - putTrees(trees) - - - case Function(vparams, body) => - putTree(body) - putTrees(vparams) - - case Assign(lhs, rhs) => - putTree(lhs) - putTree(rhs) - - case If(cond, thenp, elsep) => - putTree(cond) - putTree(thenp) - putTree(elsep) - - case Match(selector, cases) => - putTree(selector) - putTrees(cases) - - case Return(expr) => - putTree(expr) - - case Try(block, catches, finalizer) => - putTree(block) - putTree(finalizer) - putTrees(catches) - - case Throw(expr) => - putTree(expr) - - case New(tpt) => - putTree(tpt) - - case Typed(expr, tpt) => - putTree(expr) - putTree(tpt) - - case TypeApply(fun, args) => - putTree(fun) - putTrees(args) - - case Apply(fun, args) => - putTree(fun) - putTrees(args) - - case ApplyDynamic(qual, args) => - putTree(qual) - putTrees(args) - - case Super(qual, mix) => - putTree(qual) - putEntry(mix:Name) - - case This(qual) => - putEntry(qual) - - case Select(qualifier, selector) => - putTree(qualifier) - putEntry(selector) - - case Ident(name) => - putEntry(name) - - case Literal(value) => - putEntry(value) - - case TypeTree() => - - case Annotated(annot, arg) => - putTree(annot) - putTree(arg) - - case SingletonTypeTree(ref) => - putTree(ref) - - case SelectFromTypeTree(qualifier, selector) => - putTree(qualifier) - putEntry(selector) - - case CompoundTypeTree(templ: Template) => - putTree(templ) - - case AppliedTypeTree(tpt, args) => - putTree(tpt) - putTrees(args) - - case TypeBoundsTree(lo, hi) => - putTree(lo) - putTree(hi) - - case ExistentialTypeTree(tpt, whereClauses) => - putTree(tpt) - putTrees(whereClauses) + private object putTreeTraverser extends Traverser { + // Only used when pickling trees, i.e. in an argument of some Annotation + // annotations in Modifiers are removed by the typechecker + override def traverseModifiers(mods: Modifiers): Unit = if (putEntry(mods)) putEntry(mods.privateWithin) + override def traverseName(name: Name): Unit = putEntry(name) + override def traverseConstant(const: Constant): Unit = putEntry(const) + override def traverse(tree: Tree): Unit = putTree(tree) + + def put(tree: Tree): Unit = { + if (tree.canHaveAttrs) + putType(tree.tpe) + if (tree.hasSymbolField) + putSymbol(tree.symbol) + + super.traverse(tree) } } - - private def putTrees(trees: List[Tree]) = trees foreach putTree - private def putTreess(treess: List[List[Tree]]) = treess foreach putTrees - - /** only used when pickling trees, i.e. in an - * argument of some Annotation */ - private def putMods(mods: Modifiers) = if (putEntry(mods)) { - // annotations in Modifiers are removed by the typechecker - val Modifiers(_, privateWithin, Nil) = mods - putEntry(privateWithin) + private def putTree(tree: Tree) { + if (putEntry(tree)) + putTreeTraverser put tree } /** Store a constant in map index, along with anything it references. @@ -461,7 +281,7 @@ abstract class Pickler extends SubComponent { } private def putChildren(sym: Symbol, children: List[Symbol]) { - assert(putEntry((sym, children))) + putEntry(sym -> children) children foreach putSymbol } @@ -469,14 +289,10 @@ abstract class Pickler extends SubComponent { private def putAnnotation(sym: Symbol, annot: AnnotationInfo) { // if an annotation with the same arguments is applied to the // same symbol multiple times, it's only pickled once. - if (putEntry((sym, annot))) + if (putEntry(sym -> annot)) putAnnotationBody(annot) } - /** used in AnnotatedType only, i.e. annotations on types */ - private def putAnnotations(annots: List[AnnotationInfo]) { - annots foreach putAnnotation - } private def putAnnotation(annot: AnnotationInfo) { if (putEntry(annot)) putAnnotationBody(annot) @@ -510,14 +326,11 @@ abstract class Pickler extends SubComponent { /** Write a reference to object, i.e., the object's number in the map index. */ - private def writeRef(ref0: AnyRef) { - val ref = ref0 match { - case sym: Symbol => deskolemize(sym) - case _ => ref0 - } - writeNat(index(ref)) + private def writeRef(ref: AnyRef) { + writeNat(index(deskolemizeTypeSymbols(ref))) } - private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef } + private def writeRefs(refs: List[AnyRef]): Unit = refs foreach writeRef + private def writeRefsWithLength(refs: List[AnyRef]) { writeNat(refs.length) writeRefs(refs) @@ -567,446 +380,137 @@ abstract class Pickler extends SubComponent { } } - /** Write an entry */ - private def writeEntry(entry: AnyRef) { - def writeBody(entry: AnyRef): Int = entry match { - case name: Name => - writeName(name) - if (name.isTermName) TERMname else TYPEname - case NoSymbol => - NONEsym - case sym: Symbol if !isLocal(sym) => - val tag = - if (sym.isModuleClass) { - writeRef(sym.name.toTermName); EXTMODCLASSref - } else { - writeRef(sym.name); EXTref - } - if (!sym.owner.isRoot) writeRef(sym.owner) - tag - case sym: ClassSymbol => - writeSymInfo(sym) - if (sym.thisSym.tpe_* != sym.tpe_*) writeRef(sym.typeOfThis) - CLASSsym - case sym: TypeSymbol => - writeSymInfo(sym) - if (sym.isAbstractType) TYPEsym else ALIASsym - case sym: TermSymbol => - writeSymInfo(sym) - if (sym.alias != NoSymbol) writeRef(sym.alias) - if (sym.isModule) MODULEsym else VALsym - case NoType => - NOtpe - case NoPrefix => - NOPREFIXtpe - case ThisType(sym) => - writeRef(sym); THIStpe - case SingleType(pre, sym) => - writeRef(pre); writeRef(sym); SINGLEtpe - case SuperType(thistpe, supertpe) => - writeRef(thistpe); writeRef(supertpe); SUPERtpe - case ConstantType(value) => - writeRef(value); CONSTANTtpe - case TypeRef(pre, sym, args) => - writeRef(pre); writeRef(sym); writeRefs(args); TYPEREFtpe - case TypeBounds(lo, hi) => - writeRef(lo); writeRef(hi); TYPEBOUNDStpe - case tp @ RefinedType(parents, decls) => - writeRef(tp.typeSymbol); writeRefs(parents); REFINEDtpe - case ClassInfoType(parents, decls, clazz) => - writeRef(clazz); writeRefs(parents); CLASSINFOtpe - case mt @ MethodType(formals, restpe) => - writeRef(restpe); writeRefs(formals) ; METHODtpe - case mt @ NullaryMethodType(restpe) => - // reuse POLYtpe since those can never have an empty list of tparams. - // TODO: is there any way this can come back and bite us in the bottom? - // ugliness and thrift aside, this should make this somewhat more backward compatible - // (I'm not sure how old scalac's would deal with nested PolyTypes, as these used to be folded into one) - writeRef(restpe); writeRefs(Nil); POLYtpe - case PolyType(tparams, restpe) => // invar: tparams nonEmpty - writeRef(restpe); writeRefs(tparams); POLYtpe - case ExistentialType(tparams, restpe) => - writeRef(restpe); writeRefs(tparams); EXISTENTIALtpe - case c @ Constant(_) => - if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0) - else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue) - else if (c.tag == FloatTag) writeLong(floatToIntBits(c.floatValue).toLong) - else if (c.tag == DoubleTag) writeLong(doubleToLongBits(c.doubleValue)) - else if (c.tag == StringTag) writeRef(newTermName(c.stringValue)) - else if (c.tag == ClazzTag) writeRef(c.typeValue) - else if (c.tag == EnumTag) writeRef(c.symbolValue) - LITERAL + c.tag // also treats UnitTag, NullTag; no value required - case AnnotatedType(annotations, tp, selfsym) => - annotations filter (_.isStatic) match { - case Nil => writeBody(tp) // write the underlying type if there are no annotations - case staticAnnots => - if (settings.selfInAnnots && selfsym != NoSymbol) - writeRef(selfsym) - writeRef(tp) - writeRefs(staticAnnots) - ANNOTATEDtpe - } - // annotations attached to a symbol (i.e. annots on terms) - case (target: Symbol, annot@AnnotationInfo(_, _, _)) => - writeRef(target) - writeAnnotation(annot) - SYMANNOT - - case ArrayAnnotArg(args) => - args foreach writeClassfileAnnotArg - ANNOTARGARRAY - - case (target: Symbol, children: List[_]) => - writeRef(target) - writeRefs(children.asInstanceOf[List[Symbol]]) - CHILDREN - - case EmptyTree => - writeNat(EMPTYtree) - TREE - - case tree@PackageDef(pid, stats) => - writeNat(PACKAGEtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(tree.mods) - writeRef(pid) - writeRefs(stats) - TREE - - case tree@ClassDef(mods, name, tparams, impl) => - writeNat(CLASStree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(impl) - writeRefs(tparams) - TREE - - case tree@ModuleDef(mods, name, impl) => - writeNat(MODULEtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(impl) - TREE - - case tree@ValDef(mods, name, tpt, rhs) => - writeNat(VALDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(tpt) - writeRef(rhs) - TREE - - case tree@DefDef(mods, name, tparams, vparamss, tpt, rhs) => - writeNat(DEFDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRefsWithLength(tparams) - writeNat(vparamss.length) - vparamss foreach writeRefsWithLength - writeRef(tpt) - writeRef(rhs) - TREE - - case tree@TypeDef(mods, name, tparams, rhs) => - writeNat(TYPEDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(rhs) - writeRefs(tparams) - TREE - - case tree@LabelDef(name, params, rhs) => - writeNat(LABELtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - writeRef(rhs) - writeRefs(params) - TREE - - case tree@Import(expr, selectors) => - writeNat(IMPORTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(expr) - for (ImportSelector(from, _, to, _) <- selectors) { - writeRef(from) - writeRef(to) - } - TREE - - case tree@DocDef(comment, definition) => - writeNat(DOCDEFtree) - writeRef(tree.tpe) - writeRef(Constant(comment)) - writeRef(definition) - TREE - - case tree@Template(parents, self, body) => - writeNat(TEMPLATEtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRefsWithLength(parents) - writeRef(self) - writeRefs(body) - TREE - - case tree@Block(stats, expr) => - writeNat(BLOCKtree) - writeRef(tree.tpe) - writeRef(expr) - writeRefs(stats) - TREE - - case tree@CaseDef(pat, guard, body) => - writeNat(CASEtree) - writeRef(tree.tpe) - writeRef(pat) - writeRef(guard) - writeRef(body) - TREE - - case tree@Alternative(trees) => - writeNat(ALTERNATIVEtree) - writeRef(tree.tpe) - writeRefs(trees) - TREE - - case tree@Star(elem) => - writeNat(STARtree) - writeRef(tree.tpe) - writeRef(elem) - TREE - - case tree@Bind(name, body) => - writeNat(BINDtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - writeRef(body) - TREE - - case tree@UnApply(fun: Tree, args) => - writeNat(UNAPPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@ArrayValue(elemtpt, trees) => - writeNat(ARRAYVALUEtree) - writeRef(tree.tpe) - writeRef(elemtpt) - writeRefs(trees) - TREE - - case tree@Function(vparams, body) => - writeNat(FUNCTIONtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(body) - writeRefs(vparams) - TREE - - case tree@Assign(lhs, rhs) => - writeNat(ASSIGNtree) - writeRef(tree.tpe) - writeRef(lhs) - writeRef(rhs) - TREE - - case tree@If(cond, thenp, elsep) => - writeNat(IFtree) - writeRef(tree.tpe) - writeRef(cond) - writeRef(thenp) - writeRef(elsep) - TREE - - case tree@Match(selector, cases) => - writeNat(MATCHtree) - writeRef(tree.tpe) - writeRef(selector) - writeRefs(cases) - TREE - - case tree@Return(expr) => - writeNat(RETURNtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(expr) - TREE - - case tree@Try(block, catches, finalizer) => - writeNat(TREtree) - writeRef(tree.tpe) - writeRef(block) - writeRef(finalizer) - writeRefs(catches) - TREE - - case tree@Throw(expr) => - writeNat(THROWtree) - writeRef(tree.tpe) - writeRef(expr) - TREE - - case tree@New(tpt) => - writeNat(NEWtree) - writeRef(tree.tpe) - writeRef(tpt) - TREE - - case tree@Typed(expr, tpt) => - writeNat(TYPEDtree) - writeRef(tree.tpe) - writeRef(expr) - writeRef(tpt) - TREE - - case tree@TypeApply(fun, args) => - writeNat(TYPEAPPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@Apply(fun, args) => - writeNat(APPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@ApplyDynamic(qual, args) => - writeNat(APPLYDYNAMICtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - writeRefs(args) - TREE - - case tree@Super(qual, mix) => - writeNat(SUPERtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - writeRef(mix) - TREE - - case tree@This(qual) => - writeNat(THIStree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - TREE - - case tree@Select(qualifier, selector) => - writeNat(SELECTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qualifier) - writeRef(selector) - TREE - - case tree@Ident(name) => - writeNat(IDENTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - TREE - - case tree@Literal(value) => - writeNat(LITERALtree) - writeRef(tree.tpe) - writeRef(value) - TREE - - case tree@TypeTree() => - writeNat(TYPEtree) - writeRef(tree.tpe) - TREE - - case tree@Annotated(annot, arg) => - writeNat(ANNOTATEDtree) - writeRef(tree.tpe) - writeRef(annot) - writeRef(arg) - TREE - - case tree@SingletonTypeTree(ref) => - writeNat(SINGLETONTYPEtree) + private object writeTreeBodyTraverser extends Traverser { + private var refs = false + @inline private def asRefs[T](body: => T): T = { + val saved = refs + refs = true + try body finally refs = saved + } + override def traverseModifiers(mods: Modifiers): Unit = if (refs) writeRef(mods) else super.traverseModifiers(mods) + override def traverseName(name: Name): Unit = writeRef(name) + override def traverseConstant(const: Constant): Unit = writeRef(const) + override def traverseParams(params: List[Tree]): Unit = writeRefsWithLength(params) + override def traverseParamss(vparamss: List[List[Tree]]): Unit = { + writeNat(vparamss.length) + super.traverseParamss(vparamss) + } + override def traverse(tree: Tree): Unit = { + if (refs) + writeRef(tree) + else { writeRef(tree.tpe) - writeRef(ref) - TREE + if (tree.hasSymbolField) + writeRef(tree.symbol) - case tree@SelectFromTypeTree(qualifier, selector) => - writeNat(SELECTFROMTYPEtree) - writeRef(tree.tpe) - writeRef(qualifier) - writeRef(selector) - TREE + asRefs(super.traverse(tree)) + } + } + } - case tree@CompoundTypeTree(templ: Template) => - writeNat(COMPOUNDTYPEtree) - writeRef(tree.tpe) - writeRef(templ) - TREE + /** Write an entry */ + private def writeEntry(entry: AnyRef) { + def writeLocalSymbolBody(sym: Symbol) { + writeSymInfo(sym) + sym match { + case _: ClassSymbol if sym.hasSelfType => writeRef(sym.typeOfThis) + case _: TermSymbol if sym.alias.exists => writeRef(sym.alias) + case _ => + } + } + def writeExtSymbolBody(sym: Symbol) { + val name = if (sym.isModuleClass) sym.name.toTermName else sym.name + writeRef(name) + if (!sym.owner.isRoot) + writeRef(sym.owner) + } + def writeSymbolBody(sym: Symbol) { + if (sym ne NoSymbol) { + if (isLocal(sym)) + writeLocalSymbolBody(sym) + else + writeExtSymbolBody(sym) + } + } - case tree@AppliedTypeTree(tpt, args) => - writeNat(APPLIEDTYPEtree) - writeRef(tree.tpe) - writeRef(tpt) - writeRefs(args) - TREE + // NullaryMethodType reuses POLYtpe since those can never have an empty list of tparams. + // TODO: is there any way this can come back and bite us in the bottom? + // ugliness and thrift aside, this should make this somewhat more backward compatible + // (I'm not sure how old scalac's would deal with nested PolyTypes, as these used to be folded into one) + def writeTypeBody(tpe: Type): Unit = tpe match { + case NoType | NoPrefix => + case ThisType(sym) => writeRef(sym) + case SingleType(pre, sym) => writeRef(pre) ; writeRef(sym) + case SuperType(thistpe, supertpe) => writeRef(thistpe) ; writeRef(supertpe) + case ConstantType(value) => writeRef(value) + case TypeBounds(lo, hi) => writeRef(lo) ; writeRef(hi) + case TypeRef(pre, sym, args) => writeRef(pre) ; writeRef(sym); writeRefs(args) + case MethodType(formals, restpe) => writeRef(restpe) ; writeRefs(formals) + case NullaryMethodType(restpe) => writeRef(restpe); writeRefs(Nil) + case PolyType(tparams, restpe) => writeRef(restpe); writeRefs(tparams) + case ExistentialType(tparams, restpe) => writeRef(restpe); writeRefs(tparams) + case StaticallyAnnotatedType(annots, tp) => writeRef(tp) ; writeRefs(annots) + case AnnotatedType(_, tp, _) => writeTypeBody(tp) // write the underlying type if there are no static annotations + case CompoundType(parents, _, clazz) => writeRef(clazz); writeRefs(parents) + } - case tree@TypeBoundsTree(lo, hi) => - writeNat(TYPEBOUNDStree) - writeRef(tree.tpe) - writeRef(lo) - writeRef(hi) - TREE + def writeTreeBody(tree: Tree) { + writeNat(picklerSubTag(tree)) + if (!tree.isEmpty) + writeTreeBodyTraverser traverse tree + } - case tree@ExistentialTypeTree(tpt, whereClauses) => - writeNat(EXISTENTIALTYPEtree) - writeRef(tree.tpe) - writeRef(tpt) - writeRefs(whereClauses) - TREE + def writeConstant(c: Constant): Unit = c.tag match { + case BooleanTag => writeLong(if (c.booleanValue) 1 else 0) + case FloatTag => writeLong(floatToIntBits(c.floatValue).toLong) + case DoubleTag => writeLong(doubleToLongBits(c.doubleValue)) + case StringTag => writeRef(newTermName(c.stringValue)) + case ClazzTag => writeRef(c.typeValue) + case EnumTag => writeRef(c.symbolValue) + case tag => if (ByteTag <= tag && tag <= LongTag) writeLong(c.longValue) + } - case Modifiers(flags, privateWithin, _) => - val pflags = rawToPickledFlags(flags) - writeNat((pflags >> 32).toInt) - writeNat((pflags & 0xFFFFFFFF).toInt) - writeRef(privateWithin) - MODIFIERS + def writeModifiers(mods: Modifiers) { + val pflags = rawToPickledFlags(mods.flags) + writeNat((pflags >> 32).toInt) + writeNat((pflags & 0xFFFFFFFF).toInt) + writeRef(mods.privateWithin) + } - // annotations on types (not linked to a symbol) - case annot@AnnotationInfo(_, _, _) => - writeAnnotation(annot) - ANNOTINFO + def writeSymbolTuple(target: Symbol, other: Any) { + writeRef(target) + other match { + case annot: AnnotationInfo => writeAnnotation(annot) + case children: List[Symbol @unchecked] => writeRefs(children) + case _ => + } + } - case _ => - throw new FatalError("bad entry: " + entry + " " + entry.getClass) + def writeBody(entry: AnyRef): Unit = entry match { + case tree: Tree => writeTreeBody(tree) + case sym: Symbol => writeSymbolBody(sym) + case tpe: Type => writeTypeBody(tpe) + case name: Name => writeName(name) + case const: Constant => writeConstant(const) + case mods: Modifiers => writeModifiers(mods) + case annot: AnnotationInfo => writeAnnotation(annot) + case (target: Symbol, other) => writeSymbolTuple(target, other) + case ArrayAnnotArg(args) => args foreach writeClassfileAnnotArg + case _ => devWarning(s"Unexpected entry to pickler ${shortClassOfInstance(entry)} $entry") } // begin writeEntry - val startpos = writeIndex - // reserve some space so that the patchNat's most likely won't need to shift - writeByte(0); writeByte(0) - patchNat(startpos, writeBody(entry)) - patchNat(startpos + 1, writeIndex - (startpos + 2)) + // The picklerTag method can't determine if it's an external symbol reference + val tag = entry match { + case sym: Symbol if isExternalSymbol(sym) => if (sym.isModuleClass) EXTMODCLASSref else EXTref + case _ => picklerTag(entry) + } + writeNat(tag) + writeByte(0) // reserve a place to record the number of bytes written + val start = writeIndex + writeBody(entry) + val length = writeIndex - start + patchNat(start - 1, length) // patch bytes written over the placeholder } /** Write byte array */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 599969598e..e3d7bfd4f8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -425,11 +425,10 @@ trait Namers extends MethodSynthesis { sym } - /** Enter a module symbol. The tree parameter can be either - * a module definition or a class definition. + /** Enter a module symbol. */ def enterModuleSymbol(tree : ModuleDef): Symbol = { - var m: Symbol = context.scope lookupAll tree.name find (_.isModule) getOrElse NoSymbol + var m: Symbol = context.scope lookupModule tree.name val moduleFlags = tree.mods.flags | MODULE if (m.isModule && !m.isPackage && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) { updatePosFlags(m, tree.pos, moduleFlags) diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 1b726c37b9..fd8f9bebba 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -283,6 +283,9 @@ abstract class TreeCheckers extends Analyzer { } private def traverseInternal(tree: Tree) { + if (!tree.canHaveAttrs) + return + checkSymbolRefsRespectScope(enclosingMemberDefs takeWhile (md => !md.symbol.hasPackageFlag), tree) checkReturnReferencesDirectlyEnclosingDef(tree) @@ -329,10 +332,9 @@ abstract class TreeCheckers extends Analyzer { return case _ => } - - if (tree.canHaveAttrs && tree.pos == NoPosition) + if (tree.pos == NoPosition) noPos(tree) - else if (tree.tpe == null && phase.id > currentRun.typerPhase.id) + else if (tree.tpe == null && isPastTyper) noType(tree) else if (tree.isDef) { checkSym(tree) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e93c0938e3..97e9d6ef52 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -13,7 +13,7 @@ package scala package tools.nsc package typechecker -import scala.collection.mutable +import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance } import mutable.ListBuffer import symtab.Flags._ @@ -3590,7 +3590,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper else { val annScope = annType.decls .filter(sym => sym.isMethod && !sym.isConstructor && sym.isJavaDefined) - val names = new scala.collection.mutable.HashSet[Symbol] + val names = mutable.Set[Symbol]() names ++= (if (isJava) annScope.iterator else typedFun.tpe.params.iterator) @@ -3603,7 +3603,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val nvPairs = args map { case arg @ AssignOrNamedArg(Ident(name), rhs) => val sym = if (isJava) annScope.lookup(name) - else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol) + else findSymbol(typedFun.tpe.params)(_.name == name) if (sym == NoSymbol) { reportAnnotationError(UnknownAnnotationNameError(arg, name)) (nme.ERROR, None) @@ -3730,8 +3730,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper while (o != owner && o != NoSymbol && !o.hasPackageFlag) o = o.owner o == owner && !isVisibleParameter(sym) } - var localSyms = scala.collection.immutable.Set[Symbol]() - var boundSyms = scala.collection.immutable.Set[Symbol]() + var localSyms = immutable.Set[Symbol]() + var boundSyms = immutable.Set[Symbol]() def isLocal(sym: Symbol): Boolean = if (sym == NoSymbol || sym.isRefinementClass || sym.isLocalDummy) false else if (owner == NoSymbol) tree exists (defines(_, sym)) @@ -4311,7 +4311,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper NotAMemberError(tpt, TypeTree(tp), nme.CONSTRUCTOR) setError(tpt) } - else if (!( tp == sym.thisSym.tpe_* // when there's no explicit self type -- with (#3612) or without self variable + else if (!( tp == sym.typeOfThis // when there's no explicit self type -- with (#3612) or without self variable // sym.thisSym.tpe == tp.typeOfThis (except for objects) || narrowRhs(tp) <:< tp.typeOfThis || phase.erasedTypes |