From 1a1c37ce3aa75193ecf7ef3e4089cd2305728695 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 12 Oct 2013 13:22:29 -0700 Subject: Convenience method findSymbol. --- src/reflect/scala/reflect/internal/Scopes.scala | 4 ++-- src/reflect/scala/reflect/internal/SymbolTable.scala | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index 485d4d5ddd..1060b3a99c 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -221,8 +221,8 @@ trait Scopes extends api.Scopes { self: SymbolTable => /** Lookup a module or a class, filtering out matching names in scope * which do not match that requirement. */ - def lookupModule(name: Name): Symbol = lookupAll(name.toTermName) find (_.isModule) getOrElse NoSymbol - def lookupClass(name: Name): Symbol = lookupAll(name.toTypeName) find (_.isClass) getOrElse NoSymbol + def lookupModule(name: Name): Symbol = findSymbol(lookupAll(name.toTermName))(_.isModule) + def lookupClass(name: Name): Symbol = findSymbol(lookupAll(name.toTypeName))(_.isClass) /** True if the name exists in this scope, false otherwise. */ def containsName(name: Name) = lookupEntry(name) != null diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index a6f9dfc164..ff40c0108f 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -124,6 +124,10 @@ abstract class SymbolTable extends macros.Universe result } + @inline final def findSymbol(xs: TraversableOnce[Symbol])(p: Symbol => Boolean): Symbol = { + xs find p getOrElse NoSymbol + } + // For too long have we suffered in order to sort NAMES. // I'm pretty sure there's a reasonable default for that. // Notice challenge created by Ordering's invariance. -- cgit v1.2.3 From eaad52c95a4a8c7752b68931902fa63d9d4cc800 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 12 Oct 2013 13:22:29 -0700 Subject: Add -Xdev to the runtime-visible settings. --- .../internal/settings/MutableSettings.scala | 25 ++++++++++++---------- src/reflect/scala/reflect/runtime/Settings.scala | 5 +++-- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index e21e95903b..28afd18fe0 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -33,23 +33,26 @@ abstract class MutableSettings extends AbsSettings { } } - def overrideObjects: BooleanSetting - def printtypes: BooleanSetting + def Xexperimental: BooleanSetting + def XfullLubs: BooleanSetting + def XnoPatmatAnalysis: BooleanSetting + def Xprintpos: BooleanSetting + def Yposdebug: BooleanSetting + def Yrangepos: BooleanSetting + def Yshowsymkinds: BooleanSetting + def breakCycles: BooleanSetting def debug: BooleanSetting + def developer: BooleanSetting def explaintypes: BooleanSetting - def verbose: BooleanSetting + def overrideObjects: BooleanSetting + def printtypes: BooleanSetting def uniqid: BooleanSetting - def Yshowsymkinds: BooleanSetting - def Yposdebug: BooleanSetting - def Yrangepos: BooleanSetting - def Xprintpos: BooleanSetting + def verbose: BooleanSetting + def Yrecursion: IntSetting def maxClassfileName: IntSetting - def Xexperimental: BooleanSetting - def XnoPatmatAnalysis: BooleanSetting - def XfullLubs: BooleanSetting - def breakCycles: BooleanSetting } + object MutableSettings { import scala.language.implicitConversions /** Support the common use case, `if (settings.debug) println("Hello, martin.")` */ diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index d65e9329ed..11db83d7d5 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -34,16 +34,17 @@ private[reflect] class Settings extends MutableSettings { val XfullLubs = new BooleanSetting(false) val XnoPatmatAnalysis = new BooleanSetting(false) val Xprintpos = new BooleanSetting(false) - val Yshowsymkinds = new BooleanSetting(false) val Yposdebug = new BooleanSetting(false) val Yrangepos = new BooleanSetting(false) + val Yshowsymkinds = new BooleanSetting(false) + val breakCycles = new BooleanSetting(false) val debug = new BooleanSetting(false) + val developer = new BooleanSetting(false) val explaintypes = new BooleanSetting(false) val overrideObjects = new BooleanSetting(false) val printtypes = new BooleanSetting(false) val uniqid = new BooleanSetting(false) val verbose = new BooleanSetting(false) - val breakCycles = new BooleanSetting(false) val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) -- cgit v1.2.3 From 2e396cfd408b4a10b41dbca7993aae603f290ab5 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 12 Oct 2013 13:22:29 -0700 Subject: Mappings between classes and pickler tags. This enables a measure of "command/query separation", which is to say: the same method shouldn't go on a side effecting binge and also return a value. --- .../reflect/internal/pickling/Translations.scala | 128 +++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/reflect/scala/reflect/internal/pickling/Translations.scala (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/pickling/Translations.scala b/src/reflect/scala/reflect/internal/pickling/Translations.scala new file mode 100644 index 0000000000..e56cf796cb --- /dev/null +++ b/src/reflect/scala/reflect/internal/pickling/Translations.scala @@ -0,0 +1,128 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala +package reflect +package internal +package pickling + +import PickleFormat._ +import util.shortClassOfInstance + +trait Translations { + self: SymbolTable => + + def isTreeSymbolPickled(code: Int): Boolean = (code: @annotation.switch) match { + case PACKAGEtree | CLASStree | MODULEtree | VALDEFtree | DEFDEFtree | TYPEDEFtree | LABELtree => true + case IMPORTtree | TEMPLATEtree | BINDtree | FUNCTIONtree | RETURNtree => true + case APPLYDYNAMICtree | SUPERtree | THIStree | SELECTtree | IDENTtree => true + case _ => false + } + /** This method should be equivalent to tree.hasSymbolField, but that method + * doesn't do us any good when we're unpickling because we need to know based + * on the Int tag - the tree doesn't exist yet. Thus, this method is documentation only. + */ + def isTreeSymbolPickled(tree: Tree): Boolean = isTreeSymbolPickled(picklerSubTag(tree)) + + // The ad hoc pattern matching of tuples out of AnyRefs is a + // truly terrible idea. It reaches the height of its powers in + // combination with scala's insistence on helpfully tupling + // multiple arguments passed to a single-arg AnyRef. + def picklerTag(ref: AnyRef): Int = ref match { + case tp: Type => picklerTag(tp) + case sym: Symbol => picklerTag(sym) + case const: Constant => LITERAL + const.tag + case _: Tree => TREE // its sub tag more precisely identifies it + case _: TermName => TERMname + case _: TypeName => TYPEname + case _: ArrayAnnotArg => ANNOTARGARRAY // an array of annotation arguments + case _: AnnotationInfo => ANNOTINFO // annotations on types (not linked to a symbol) + case (_: Symbol, _: AnnotationInfo) => SYMANNOT // symbol annotations, i.e. on terms + case (_: Symbol, _: List[_]) => CHILDREN // the direct subclasses of a sealed symbol + case _: Modifiers => MODIFIERS + case _ => sys.error(s"unpicklable entry ${shortClassOfInstance(ref)} $ref") + } + + /** Local symbols only. The assessment of locality depends + * on convoluted conditions which depends in part on the root + * symbol being pickled, so it cannot be reproduced here. + * The pickler tags at stake are EXTMODCLASSref and EXTref. + * Those tags are never produced here - such symbols must be + * excluded prior to calling this method. + */ + def picklerTag(sym: Symbol): Int = sym match { + case NoSymbol => NONEsym + case _: ClassSymbol => CLASSsym + case _: TypeSymbol if sym.isAbstractType => TYPEsym + case _: TypeSymbol => ALIASsym + case _: TermSymbol if sym.isModule => MODULEsym + case _: TermSymbol => VALsym + } + + def picklerTag(tpe: Type): Int = tpe match { + case NoType => NOtpe + case NoPrefix => NOPREFIXtpe + case _: ThisType => THIStpe + case _: SingleType => SINGLEtpe + case _: SuperType => SUPERtpe + case _: ConstantType => CONSTANTtpe + case _: TypeBounds => TYPEBOUNDStpe + case _: TypeRef => TYPEREFtpe + case _: RefinedType => REFINEDtpe + case _: ClassInfoType => CLASSINFOtpe + case _: MethodType => METHODtpe + case _: PolyType => POLYtpe + case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium! + case _: ExistentialType => EXISTENTIALtpe + case _: AnnotatedType => ANNOTATEDtpe + } + + def picklerSubTag(tree: Tree): Int = tree match { + case EmptyTree => EMPTYtree + case _: PackageDef => PACKAGEtree + case _: ClassDef => CLASStree + case _: ModuleDef => MODULEtree + case _: ValDef => VALDEFtree + case _: DefDef => DEFDEFtree + case _: TypeDef => TYPEDEFtree + case _: LabelDef => LABELtree + case _: Import => IMPORTtree + // case _: DocDef => DOCDEFtree + case _: Template => TEMPLATEtree + case _: Block => BLOCKtree + case _: CaseDef => CASEtree + case _: Alternative => ALTERNATIVEtree + case _: Star => STARtree + case _: Bind => BINDtree + case _: UnApply => UNAPPLYtree + case _: ArrayValue => ARRAYVALUEtree + case _: Function => FUNCTIONtree + case _: Assign => ASSIGNtree + case _: If => IFtree + case _: Match => MATCHtree + case _: Return => RETURNtree + case _: Try => TREtree // TREtree? + case _: Throw => THROWtree + case _: New => NEWtree + case _: Typed => TYPEDtree + case _: TypeApply => TYPEAPPLYtree + case _: Apply => APPLYtree + case _: ApplyDynamic => APPLYDYNAMICtree + case _: Super => SUPERtree + case _: This => THIStree + case _: Select => SELECTtree + case _: Ident => IDENTtree + case _: Literal => LITERALtree + case _: TypeTree => TYPEtree + case _: Annotated => ANNOTATEDtree + case _: SingletonTypeTree => SINGLETONTYPEtree + case _: SelectFromTypeTree => SELECTFROMTYPEtree + case _: CompoundTypeTree => COMPOUNDTYPEtree + case _: AppliedTypeTree => APPLIEDTYPEtree + case _: TypeBoundsTree => TYPEBOUNDStree + case _: ExistentialTypeTree => EXISTENTIALTYPEtree + } +} + -- cgit v1.2.3 From 351a3e0da6bf84bcdfdd1b0fb02f16c0d9896cb1 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 12 Oct 2013 13:22:29 -0700 Subject: Tree traversal: more uniform and granular. There's a huge amount of tree traversal related duplication which is hard to eliminate only because trees aren't properly traversed. The not-quite-tree bits of key trees are ignored during traversals, making it impossible to write e.g. a pretty printer without duplicating almost the entire traversal logic (as indeed is done for printing purposes in more than one place.) And almost the entire pickler logic is redundant with Traverser, except since it's all duplicated of course it diverged. The pickler issue is remedied in the commit to follow. The not-quite-trees not quite being traversed were Modifiers, Name, ImportSelector, and Constant. Now every case field of every tree is traversed, with classes which aren't trees traversed via the following methods, default implementations as shown: def traverseName(name: Name): Unit = () def traverseConstant(c: Constant): Unit = () def traverseImportSelector(sel: ImportSelector): Unit = () def traverseModifiers(mods: Modifiers): Unit = traverseAnnotations(mods.annotations) --- src/reflect/scala/reflect/api/Trees.scala | 28 +++- src/reflect/scala/reflect/internal/Trees.scala | 173 +++++++++++++++---------- 2 files changed, 122 insertions(+), 79 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index fa7d41f0fc..241747e6d8 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -2544,18 +2544,32 @@ trait Trees { self: Universe => class Traverser { protected[scala] var currentOwner: Symbol = rootMirror.RootClass + /** Traverse something which Trees contain, but which isn't a Tree itself. */ + def traverseName(name: Name): Unit = () + def traverseConstant(c: Constant): Unit = () + def traverseImportSelector(sel: ImportSelector): Unit = () + def traverseModifiers(mods: Modifiers): Unit = traverseAnnotations(mods.annotations) + /** Traverses a single tree. */ - def traverse(tree: Tree): Unit = itraverse(this, tree) + def traverse(tree: Tree): Unit = itraverse(this, tree) + def traversePattern(pat: Tree): Unit = traverse(pat) + def traverseGuard(guard: Tree): Unit = traverse(guard) + def traverseTypeAscription(tpt: Tree): Unit = traverse(tpt) + // Special handling of noSelfType necessary for backward compat: existing + // traversers break down when they see the unexpected tree. + def traverseSelfType(self: ValDef): Unit = if (self ne noSelfType) traverse(self) /** Traverses a list of trees. */ - def traverseTrees(trees: List[Tree]) { - trees foreach traverse - } + def traverseTrees(trees: List[Tree]): Unit = trees foreach traverse + def traverseTypeArgs(args: List[Tree]): Unit = traverseTrees(args) + def traverseParents(parents: List[Tree]): Unit = traverseTrees(parents) + def traverseCases(cases: List[CaseDef]): Unit = traverseTrees(cases) + def traverseAnnotations(annots: List[Tree]): Unit = traverseTrees(annots) /** Traverses a list of lists of trees. */ - def traverseTreess(treess: List[List[Tree]]) { - treess foreach traverseTrees - } + def traverseTreess(treess: List[List[Tree]]): Unit = treess foreach traverseTrees + def traverseParams(params: List[Tree]): Unit = traverseTrees(params) + def traverseParamss(vparamss: List[List[Tree]]): Unit = vparamss foreach traverseParams /** Traverses a list of trees with a given owner symbol. */ def traverseStats(stats: List[Tree], exprOwner: Symbol) { diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index ccf5cf5249..bc1a111faa 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -8,10 +8,12 @@ package reflect package internal import Flags._ -import scala.collection.mutable.{ListBuffer, LinkedHashSet} +import pickling.PickleFormat._ +import scala.collection.{ mutable, immutable } import util.Statistics -trait Trees extends api.Trees { self: SymbolTable => +trait Trees extends api.Trees { + self: SymbolTable => private[scala] var nodeCount = 0 @@ -160,7 +162,7 @@ trait Trees extends api.Trees { self: SymbolTable => override def freeTypes: List[FreeTypeSymbol] = freeSyms[FreeTypeSymbol](_.isFreeType, _.typeSymbol) private def freeSyms[S <: Symbol](isFree: Symbol => Boolean, symOfType: Type => Symbol): List[S] = { - val s = scala.collection.mutable.LinkedHashSet[S]() + val s = mutable.LinkedHashSet[S]() def addIfFree(sym: Symbol): Unit = if (sym != null && isFree(sym)) s += sym.asInstanceOf[S] for (t <- this) { addIfFree(t.symbol) @@ -1019,18 +1021,22 @@ trait Trees extends api.Trees { self: SymbolTable => } trait CannotHaveAttrs extends Tree { - override def canHaveAttrs = false - - private def requireLegal(value: Any, allowed: Any, what: String) = - require(value == allowed, s"can't set $what for $self to value other than $allowed") - super.setPos(NoPosition) + super.setType(NoType) + + override def canHaveAttrs = false override def setPos(pos: Position) = { requireLegal(pos, NoPosition, "pos"); this } override def pos_=(pos: Position) = setPos(pos) - - super.setType(NoType) override def setType(t: Type) = { requireLegal(t, NoType, "tpe"); this } override def tpe_=(t: Type) = setType(t) + + private def requireLegal(value: Any, allowed: Any, what: String) = ( + if (value != allowed) { + log(s"can't set $what for $self to value other than $allowed") + if (settings.debug && settings.developer) + (new Throwable).printStackTrace + } + ) } case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) } @@ -1159,113 +1165,136 @@ trait Trees extends api.Trees { self: SymbolTable => override protected def itraverse(traverser: Traverser, tree: Tree): Unit = { import traverser._ - tree match { - case EmptyTree => - ; - case PackageDef(pid, stats) => - traverse(pid) - atOwner(mclass(tree.symbol)) { - traverseTrees(stats) - } - case ClassDef(mods, name, tparams, impl) => - atOwner(tree.symbol) { - traverseTrees(mods.annotations); traverseTrees(tparams); traverse(impl) - } - case ModuleDef(mods, name, impl) => - atOwner(mclass(tree.symbol)) { - traverseTrees(mods.annotations); traverse(impl) - } - case ValDef(mods, name, tpt, rhs) => - atOwner(tree.symbol) { - traverseTrees(mods.annotations); traverse(tpt); traverse(rhs) - } - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - atOwner(tree.symbol) { - traverseTrees(mods.annotations); traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs) - } - case TypeDef(mods, name, tparams, rhs) => - atOwner(tree.symbol) { - traverseTrees(mods.annotations); traverseTrees(tparams); traverse(rhs) - } + + def traverseMemberDef(md: MemberDef, owner: Symbol): Unit = atOwner(owner) { + traverseModifiers(md.mods) + traverseName(md.name) + md match { + case ClassDef(_, _, tparams, impl) => traverseParams(tparams) ; traverse(impl) + case ModuleDef(_, _, impl) => traverse(impl) + case ValDef(_, _, tpt, rhs) => traverseTypeAscription(tpt) ; traverse(rhs) + case TypeDef(_, _, tparams, rhs) => traverseParams(tparams) ; traverse(rhs) + case DefDef(_, _, tparams, vparamss, tpt, rhs) => + traverseParams(tparams) + traverseParamss(vparamss) + traverseTypeAscription(tpt) + traverse(rhs) + } + } + def traverseComponents(): Unit = tree match { case LabelDef(name, params, rhs) => - traverseTrees(params); traverse(rhs) + traverseName(name) + traverseParams(params) + traverse(rhs) case Import(expr, selectors) => traverse(expr) + selectors foreach traverseImportSelector case Annotated(annot, arg) => - traverse(annot); traverse(arg) + traverse(annot) + traverse(arg) case Template(parents, self, body) => - traverseTrees(parents) - if (self ne noSelfType) traverse(self) + traverseParents(parents) + traverseSelfType(self) traverseStats(body, tree.symbol) case Block(stats, expr) => - traverseTrees(stats); traverse(expr) + traverseTrees(stats) + traverse(expr) case CaseDef(pat, guard, body) => - traverse(pat); traverse(guard); traverse(body) + traversePattern(pat) + traverseGuard(guard) + traverse(body) case Alternative(trees) => traverseTrees(trees) case Star(elem) => traverse(elem) case Bind(name, body) => + traverseName(name) traverse(body) case UnApply(fun, args) => - traverse(fun); traverseTrees(args) + traverse(fun) + traverseTrees(args) case ArrayValue(elemtpt, trees) => - traverse(elemtpt); traverseTrees(trees) - case Function(vparams, body) => - atOwner(tree.symbol) { - traverseTrees(vparams); traverse(body) - } + traverse(elemtpt) + traverseTrees(trees) case Assign(lhs, rhs) => - traverse(lhs); traverse(rhs) + traverse(lhs) + traverse(rhs) case AssignOrNamedArg(lhs, rhs) => - traverse(lhs); traverse(rhs) + traverse(lhs) + traverse(rhs) case If(cond, thenp, elsep) => - traverse(cond); traverse(thenp); traverse(elsep) + traverse(cond) + traverse(thenp) + traverse(elsep) case Match(selector, cases) => - traverse(selector); traverseTrees(cases) + traverse(selector) + traverseCases(cases) case Return(expr) => traverse(expr) case Try(block, catches, finalizer) => - traverse(block); traverseTrees(catches); traverse(finalizer) + traverse(block) + traverseCases(catches) + traverse(finalizer) case Throw(expr) => traverse(expr) case New(tpt) => traverse(tpt) case Typed(expr, tpt) => - traverse(expr); traverse(tpt) + traverse(expr) + traverseTypeAscription(tpt) case TypeApply(fun, args) => - traverse(fun); traverseTrees(args) + traverse(fun) + traverseTypeArgs(args) case Apply(fun, args) => - traverse(fun); traverseTrees(args) + traverse(fun) + traverseTrees(args) case ApplyDynamic(qual, args) => - traverse(qual); traverseTrees(args) - case Super(qual, _) => traverse(qual) - case This(_) => - ; + traverseTrees(args) + case Super(qual, mix) => + traverse(qual) + traverseName(mix) + case This(qual) => + traverseName(qual) case Select(qualifier, selector) => traverse(qualifier) - case Ident(_) => - ; + traverseName(selector) + case Ident(name) => + traverseName(name) case ReferenceToBoxed(idt) => traverse(idt) - case Literal(_) => - ; + case Literal(const) => + traverseConstant(const) case TypeTree() => ; case SingletonTypeTree(ref) => traverse(ref) case SelectFromTypeTree(qualifier, selector) => traverse(qualifier) + traverseName(selector) case CompoundTypeTree(templ) => traverse(templ) case AppliedTypeTree(tpt, args) => - traverse(tpt); traverseTrees(args) + traverse(tpt) + traverseTypeArgs(args) case TypeBoundsTree(lo, hi) => - traverse(lo); traverse(hi) + traverse(lo) + traverse(hi) case ExistentialTypeTree(tpt, whereClauses) => - traverse(tpt); traverseTrees(whereClauses) - case _ => xtraverse(traverser, tree) + traverse(tpt) + traverseTrees(whereClauses) + case _ => + xtraverse(traverser, tree) + } + + if (tree.canHaveAttrs) { + tree match { + case PackageDef(pid, stats) => traverse(pid) ; traverseStats(stats, mclass(tree.symbol)) + case md: ModuleDef => traverseMemberDef(md, mclass(tree.symbol)) + case md: MemberDef => traverseMemberDef(md, tree.symbol) + case Function(vparams, body) => atOwner(tree.symbol) { traverseParams(vparams) ; traverse(body) } + case _ => traverseComponents() + } } } @@ -1563,7 +1592,7 @@ trait Trees extends api.Trees { self: SymbolTable => } class FilterTreeTraverser(p: Tree => Boolean) extends Traverser { - val hits = new ListBuffer[Tree] + val hits = mutable.ListBuffer[Tree]() override def traverse(t: Tree) { if (p(t)) hits += t super.traverse(t) @@ -1571,7 +1600,7 @@ trait Trees extends api.Trees { self: SymbolTable => } class CollectTreeTraverser[T](pf: PartialFunction[Tree, T]) extends Traverser { - val results = new ListBuffer[T] + val results = mutable.ListBuffer[T]() override def traverse(t: Tree) { if (pf.isDefinedAt(t)) results += pf(t) super.traverse(t) -- cgit v1.2.3 From 1edddfa7fd3066b2c336eb16f105283f5e9c18cd Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 12 Oct 2013 13:22:29 -0700 Subject: Eliminate redundant pickling code. This commit drops about 700 lines of redundant traversal logic. There had been ad hoc adjustments to the pickling scheme here and there, probably in pursuit of tiny performance improvements. For instance, a Block was pickled expr/stats instead of stats/expr, a TypeDef was pickled rhs/tparams instead of tparams/rhs. The benefits derived are invisible compared to the cost of having several hundred lines of tree traversal code duplicated in half a dozen or more places. After making Traverser consistent/complete, it was a straightforward matter to use it for pickling. It is ALSO now possible to write a vastly cleaner tree printer than the ones presently in trunk, but I leave this as an exercise for Dear Reviewer. --- .../scala/tools/nsc/symtab/classfile/Pickler.scala | 850 +++++---------------- .../scala/tools/nsc/typechecker/Namers.scala | 5 +- .../scala/tools/nsc/typechecker/TreeCheckers.scala | 8 +- .../scala/tools/nsc/typechecker/Typers.scala | 10 +- .../scala/reflect/internal/AnnotationInfos.scala | 2 + .../scala/reflect/internal/SymbolTable.scala | 1 + src/reflect/scala/reflect/internal/Symbols.scala | 2 + src/reflect/scala/reflect/internal/Types.scala | 15 + src/reflect/scala/reflect/internal/Variances.scala | 3 +- .../reflect/internal/pickling/UnPickler.scala | 510 ++++--------- 10 files changed, 369 insertions(+), 1037 deletions(-) (limited to 'src/reflect') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index a46da92233..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._ @@ -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 6dadb3100f..3826c819f9 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._ @@ -3405,7 +3405,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) @@ -3545,8 +3545,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)) @@ -4126,7 +4126,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 diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 215ab6abd6..f45fa40f89 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -27,6 +27,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => def filterAnnotations(p: AnnotationInfo => Boolean): Self // Retain only annotations meeting the condition. def withoutAnnotations: Self // Remove all annotations from this type. + def staticAnnotations = annotations filter (_.isStatic) + /** Symbols of any @throws annotations on this symbol. */ def throwsAnnotations(): List[Symbol] = annotations collect { diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index ff40c0108f..98466ebb2b 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -41,6 +41,7 @@ abstract class SymbolTable extends macros.Universe with StdCreators with BuildUtils with PrivateWithin + with pickling.Translations { val gen = new TreeGen { val global: SymbolTable.this.type = SymbolTable.this } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index efdc8f7435..71de02ef9e 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -1859,6 +1859,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def thisSym: Symbol = this + def hasSelfType = thisSym.tpeHK != this.tpeHK + /** The type of `this` in a class, or else the type of the symbol itself. */ def typeOfThis = thisSym.tpe_* diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 85dfa037ec..08874d16bd 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1471,6 +1471,14 @@ trait Types } } + object CompoundType { + def unapply(tp: Type): Option[(List[Type], Scope, Symbol)] = tp match { + case ClassInfoType(parents, decls, clazz) => Some((parents, decls, clazz)) + case RefinedType(parents, decls) => Some((parents, decls, tp.typeSymbol)) + case _ => None + } + } + /** A common base class for intersection types and class types */ abstract class CompoundType extends Type { @@ -3293,6 +3301,13 @@ trait Types object AnnotatedType extends AnnotatedTypeExtractor + object StaticallyAnnotatedType { + def unapply(tp: Type): Option[(List[AnnotationInfo], Type)] = tp.staticAnnotations match { + case Nil => None + case annots => Some((annots, tp.withoutAnnotations)) + } + } + /** A class representing types with a name. When an application uses * named arguments, the named argument types for calling isApplicable * are represented as NamedType. diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index bf00a7ac87..5280467055 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -142,7 +142,8 @@ trait Variances { // No variance check for object-private/protected methods/values. // Or constructors, or case class factory or extractor. def skip = ( - sym.hasLocalFlag + sym == NoSymbol + || sym.hasLocalFlag || sym.owner.isConstructor || sym.owner.isCaseApplyOrUnapply ) diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index f42dbf56e1..c4f1f0cf96 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -65,36 +65,38 @@ abstract class UnPickler { /** A map from symbols to their associated `decls` scopes */ private val symScopes = mutable.HashMap[Symbol, Scope]() + private def expect(expected: Int, msg: => String) { + val tag = readByte() + if (tag != expected) + errorBadSignature(s"$msg ($tag)") + } + //println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug + @inline private def runAtIndex[T](i: Int)(body: => T): T = { + val saved = readIndex + readIndex = index(i) + try body finally readIndex = saved + } + // Laboriously unrolled for performance. def run() { var i = 0 while (i < index.length) { - if (entries(i) == null && isSymbolEntry(i)) { - val savedIndex = readIndex - readIndex = index(i) - entries(i) = readSymbol() - readIndex = savedIndex - } + if (entries(i) == null && isSymbolEntry(i)) + runAtIndex(i)(entries(i) = readSymbol()) + 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 - } + if (isSymbolAnnotationEntry(i)) + runAtIndex(i)(readSymbolAnnotation()) + else if (isChildrenEntry(i)) + runAtIndex(i)(readChildren()) } i += 1 } @@ -145,6 +147,11 @@ abstract class UnPickler { tag == CHILDREN } + private def maybeReadSymbol(): Either[Int, Symbol] = readNat() match { + case index if isSymbolRef(index) => Right(at(index, readSymbol)) + case index => Left(index) + } + /** Does entry represent a refinement symbol? * pre: Entry is a class symbol */ @@ -256,14 +263,11 @@ abstract class UnPickler { val name = at(nameref, readName) val owner = readSymbolRef() val flags = pickledToRawFlags(readLongNat()) - var inforef = readNat() - val privateWithin = - if (!isSymbolRef(inforef)) NoSymbol - else { - val pw = at(inforef, readSymbol) - inforef = readNat() - pw - } + + val (privateWithin, inforef) = maybeReadSymbol() match { + case Left(index) => NoSymbol -> index + case Right(sym) => sym -> readNat() + } def isModuleFlag = (flags & MODULE) != 0L def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) @@ -305,7 +309,7 @@ abstract class UnPickler { sym case MODULEsym => - val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... () + val clazz = at(inforef, () => readType()).typeSymbol // after NMT_TRANSITION, we can leave off the () => ... () if (isModuleRoot) moduleRoot setFlag pflags else owner.newLinkedModule(clazz, pflags) case VALsym => @@ -317,84 +321,48 @@ abstract class UnPickler { }) } - /** 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(forceProperType: Boolean = false): Type = { val tag = readByte() val end = readEnd() + @inline def all[T](body: => T): List[T] = until(end, () => body) + + def readTypes() = all(readTypeRef) + def readSymbols() = all(readSymbolRef) + def readAnnots() = all(readAnnotationRef) + + // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType. + // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct + // alternative after parsing the arguments. + def MethodTypeRef(restpe: Type, params: List[Symbol]): Type = ( + if (restpe == NoType || (params contains NoSymbol)) NoType + else MethodType(params, restpe) + ) + def PolyOrNullaryType(restpe: Type, tparams: List[Symbol]): Type = tparams match { + case Nil => NullaryMethodType(restpe) + case _ => PolyType(tparams, restpe) + } + def CompoundType(clazz: Symbol, parents: List[Type]): Type = tag match { + case REFINEDtpe => RefinedType(parents, symScope(clazz), clazz) + case CLASSINFOtpe => ClassInfoType(parents, symScope(clazz), clazz) + } + + // We're stuck with the order types are pickled in, but with judicious use + // of named parameters we can recapture a declarative flavor in a few cases. + // But it's still a rat's nest of adhockery. (tag: @switch) match { - case NOtpe => - NoType - case NOPREFIXtpe => - NoPrefix - case THIStpe => - ThisType(readSymbolRef()) - case SINGLEtpe => - SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType - case SUPERtpe => - val thistpe = readTypeRef() - val supertpe = readTypeRef() - SuperType(thistpe, supertpe) - case CONSTANTtpe => - ConstantType(readConstantRef()) - case TYPEREFtpe => - val pre = readTypeRef() - val sym = readSymbolRef() - val args = until(end, readTypeRef) - TypeRef(pre, sym, args) - case TYPEBOUNDStpe => - TypeBounds(readTypeRef(), readTypeRef()) - case REFINEDtpe => - val clazz = readSymbolRef() - RefinedType(until(end, readTypeRef), symScope(clazz), clazz) - case CLASSINFOtpe => - val clazz = readSymbolRef() - ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz) - case METHODtpe | IMPLICITMETHODtpe => - val restpe = readTypeRef() - val params = until(end, readSymbolRef) - // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType. - // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct - // alternative after parsing the arguments. - if (params.contains(NoSymbol) || restpe == NoType) NoType - else MethodType(params, restpe) - case POLYtpe => - val restpe = readTypeRef() - val typeParams = until(end, readSymbolRef) - if (typeParams.nonEmpty) { - // NMT_TRANSITION: old class files denoted a polymorphic nullary method as PolyType(tps, restpe), we now require PolyType(tps, NullaryMethodType(restpe)) - // when a type of kind * is expected (forceProperType is true), we know restpe should be wrapped in a NullaryMethodType (if it wasn't suitably wrapped yet) - def transitionNMT(restpe: Type) = { - val resTpeCls = restpe.getClass.toString // what's uglier than isInstanceOf? right! -- isInstanceOf does not work since the concrete types are defined in the compiler (not in scope here) - if(forceProperType /*&& pickleformat < 2.9 */ && !(resTpeCls.endsWith("MethodType"))) { assert(!resTpeCls.contains("ClassInfoType")) - NullaryMethodType(restpe) } - else restpe - } - PolyType(typeParams, transitionNMT(restpe)) - } - else - NullaryMethodType(restpe) - case EXISTENTIALtpe => - val restpe = readTypeRef() - newExistentialType(until(end, readSymbolRef), restpe) - - case ANNOTATEDtpe => - var typeRef = readNat() - val selfsym = if (isSymbolRef(typeRef)) { - val s = at(typeRef, readSymbol) - typeRef = readNat() - s - } else NoSymbol // selfsym can go. - val tp = at(typeRef, () => readType(forceProperType)) // NMT_TRANSITION - val annots = until(end, readAnnotationRef) - if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym) - else tp - case _ => - noSuchTypeTag(tag, end) + case NOtpe => NoType + case NOPREFIXtpe => NoPrefix + case THIStpe => ThisType(readSymbolRef()) + case SINGLEtpe => SingleType(readTypeRef(), readSymbolRef()) + case SUPERtpe => SuperType(readTypeRef(), readTypeRef()) + case CONSTANTtpe => ConstantType(readConstantRef()) + case TYPEREFtpe => TypeRef(readTypeRef(), readSymbolRef(), readTypes()) + case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef()) + case REFINEDtpe | CLASSINFOtpe => CompoundType(readSymbolRef(), readTypes()) + case METHODtpe => MethodTypeRef(readTypeRef(), readSymbols()) + case POLYtpe => PolyOrNullaryType(readTypeRef(), readSymbols()) + case EXISTENTIALtpe => ExistentialType(underlying = readTypeRef(), quantified = readSymbols()) + case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots(), selfsym = NoSymbol) } } @@ -483,9 +451,7 @@ abstract class UnPickler { * the symbol it requests. Called at top-level, for all * (symbol, annotInfo) entries. */ protected def readSymbolAnnotation() { - val tag = readByte() - if (tag != SYMANNOT) - errorBadSignature("symbol annotation expected ("+ tag +")") + expect(SYMANNOT, "symbol annotation expected") val end = readEnd() val target = readSymbolRef() target.addAnnotation(readAnnotationInfo(end)) @@ -501,260 +467,100 @@ abstract class UnPickler { readAnnotationInfo(end) } - /* Read an abstract syntax tree */ - protected def readTree(): Tree = { - val outerTag = readByte() - if (outerTag != TREE) - errorBadSignature("tree expected (" + outerTag + ")") - val end = readEnd() - 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() { - symbol = readSymbolRef() - mods = readModifiersRef() - name = readNameRef() + private def readNonEmptyTree(tag: Int, end: Int): Tree = { + @inline def all[T](body: => T): List[T] = until(end, () => body) + @inline def rep[T](body: => T): List[T] = times(readNat(), () => body) + + // !!! What is this doing here? + def fixApply(tree: Apply, tpe: Type): Apply = { + val Apply(fun, args) = tree + if (fun.symbol.isOverloaded) { + fun setType fun.symbol.info + inferMethodAlternative(fun, args map (_.tpe), tpe) + } + tree } - /* Read a Symbol and a Name */ - def setSymName() { - symbol = readSymbolRef() - name = readNameRef() + def ref() = readTreeRef() + def caseRef() = readCaseDefRef() + def modsRef() = readModifiersRef() + def implRef() = readTemplateRef() + def nameRef() = readNameRef() + def tparamRef() = readTypeDefRef() + def vparamRef() = readValDefRef() + def constRef() = readConstantRef() + def idRef() = readIdentRef() + def termNameRef() = readNameRef().toTermName + def typeNameRef() = readNameRef().toTypeName + def refTreeRef() = ref() match { + case t: RefTree => t + case t => errorBadSignature("RefTree expected, found " + t.shortClass) } - /* Read a Symbol */ - def setSym() { - symbol = readSymbolRef() + def selectorsRef() = all(ImportSelector(nameRef(), -1, nameRef(), -1)) + + /** A few of the most popular trees have been pulled to the top for + * switch efficiency purposes. + */ + def readTree(tpe: Type): Tree = (tag: @switch) match { + case IDENTtree => Ident(nameRef) + case SELECTtree => Select(ref, nameRef) + case APPLYtree => fixApply(Apply(ref, all(ref)), tpe) // !!! + case BINDtree => Bind(nameRef, ref) + case BLOCKtree => all(ref) match { case stats :+ expr => Block(stats, expr) } + case IFtree => If(ref, ref, ref) + case LITERALtree => Literal(constRef) + case TYPEAPPLYtree => TypeApply(ref, all(ref)) + case TYPEDtree => Typed(ref, ref) + case ALTERNATIVEtree => Alternative(all(ref)) + case ANNOTATEDtree => Annotated(ref, ref) + case APPLIEDTYPEtree => AppliedTypeTree(ref, all(ref)) + case APPLYDYNAMICtree => ApplyDynamic(ref, all(ref)) + case ARRAYVALUEtree => ArrayValue(ref, all(ref)) + case ASSIGNtree => Assign(ref, ref) + case CASEtree => CaseDef(ref, ref, ref) + case CLASStree => ClassDef(modsRef, typeNameRef, rep(tparamRef), implRef) + case COMPOUNDTYPEtree => CompoundTypeTree(implRef) + case DEFDEFtree => DefDef(modsRef, termNameRef, rep(tparamRef), rep(rep(vparamRef)), ref, ref) + case EXISTENTIALTYPEtree => ExistentialTypeTree(ref, all(ref)) + case FUNCTIONtree => Function(rep(vparamRef), ref) + case IMPORTtree => Import(ref, selectorsRef) + case LABELtree => LabelDef(termNameRef, rep(idRef), ref) + case MATCHtree => Match(ref, all(caseRef)) + case MODULEtree => ModuleDef(modsRef, termNameRef, implRef) + case NEWtree => New(ref) + case PACKAGEtree => PackageDef(refTreeRef, all(ref)) + case RETURNtree => Return(ref) + case SELECTFROMTYPEtree => SelectFromTypeTree(ref, typeNameRef) + case SINGLETONTYPEtree => SingletonTypeTree(ref) + case STARtree => Star(ref) + case SUPERtree => Super(ref, typeNameRef) + case TEMPLATEtree => Template(rep(ref), vparamRef, all(ref)) + case THIStree => This(typeNameRef) + case THROWtree => Throw(ref) + case TREtree => Try(ref, rep(caseRef), ref) + case TYPEBOUNDStree => TypeBoundsTree(ref, ref) + case TYPEDEFtree => TypeDef(modsRef, typeNameRef, rep(tparamRef), ref) + case TYPEtree => TypeTree() + case UNAPPLYtree => UnApply(ref, all(ref)) + case VALDEFtree => ValDef(modsRef, termNameRef, ref, ref) + case _ => noSuchTreeTag(tag, end) } - val t = 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) - ClassDef(mods, name.toTypeName, tparams, impl) - - case MODULEtree => - setSymModsName() - ModuleDef(mods, name.toTermName, readTemplateRef()) - - case VALDEFtree => - setSymModsName() - val tpt = readTreeRef() - val rhs = readTreeRef() - ValDef(mods, name.toTermName, tpt, rhs) - - case DEFDEFtree => - setSymModsName() - val tparams = times(readNat(), readTypeDefRef) - val vparamss = times(readNat(), () => times(readNat(), readValDefRef)) - val tpt = readTreeRef() - val rhs = readTreeRef() - DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs) - - case TYPEDEFtree => - setSymModsName() - val rhs = readTreeRef() - val tparams = until(end, readTypeDefRef) - TypeDef(mods, name.toTypeName, tparams, rhs) - - case LABELtree => - setSymName() - val rhs = readTreeRef() - val params = until(end, readIdentRef) - LabelDef(name.toTermName, params, rhs) - - case IMPORTtree => - setSym() - val expr = readTreeRef() - val selectors = until(end, () => { - val from = readNameRef() - val to = readNameRef() - ImportSelector(from, -1, to, -1) - }) - - Import(expr, selectors) - - case TEMPLATEtree => - setSym() - val parents = times(readNat(), readTreeRef) - val self = readValDefRef() - val body = until(end, readTreeRef) - - Template(parents, self, body) - - case BLOCKtree => - val expr = readTreeRef() - val stats = until(end, readTreeRef) - Block(stats, expr) - - case CASEtree => - val pat = readTreeRef() - val guard = readTreeRef() - val body = readTreeRef() - CaseDef(pat, guard, body) - - case ALTERNATIVEtree => - Alternative(until(end, readTreeRef)) - - case STARtree => - Star(readTreeRef()) - - case BINDtree => - setSymName() - Bind(name, readTreeRef()) - - case UNAPPLYtree => - val fun = readTreeRef() - val args = until(end, readTreeRef) - UnApply(fun, args) - - case ARRAYVALUEtree => - val elemtpt = readTreeRef() - val trees = until(end, readTreeRef) - ArrayValue(elemtpt, trees) - - case FUNCTIONtree => - setSym() - val body = readTreeRef() - val vparams = until(end, readValDefRef) - Function(vparams, body) - - case ASSIGNtree => - val lhs = readTreeRef() - val rhs = readTreeRef() - Assign(lhs, rhs) - - case IFtree => - val cond = readTreeRef() - val thenp = readTreeRef() - val elsep = readTreeRef() - If(cond, thenp, elsep) - - case MATCHtree => - val selector = readTreeRef() - val cases = until(end, readCaseDefRef) - Match(selector, cases) - - case RETURNtree => - setSym() - Return(readTreeRef()) - - case TREtree => - val block = readTreeRef() - val finalizer = readTreeRef() - val catches = until(end, readCaseDefRef) - Try(block, catches, finalizer) - - case THROWtree => - Throw(readTreeRef()) - - case NEWtree => - New(readTreeRef()) - - case TYPEDtree => - val expr = readTreeRef() - val tpt = readTreeRef() - Typed(expr, tpt) - - case TYPEAPPLYtree => - val fun = readTreeRef() - val args = until(end, readTreeRef) - TypeApply(fun, args) - - case APPLYtree => - val fun = readTreeRef() - val args = until(end, readTreeRef) - if (fun.symbol.isOverloaded) { - fun.setType(fun.symbol.info) - inferMethodAlternative(fun, args map (_.tpe), tpe) - } - Apply(fun, args) - - case APPLYDYNAMICtree => - setSym() - val qual = readTreeRef() - val args = until(end, readTreeRef) - ApplyDynamic(qual, args) - - case SUPERtree => - setSym() - val qual = readTreeRef() - val mix = readTypeNameRef() - Super(qual, mix) - - case THIStree => - setSym() - This(readTypeNameRef()) - - case SELECTtree => - setSym() - val qualifier = readTreeRef() - val selector = readNameRef() - Select(qualifier, selector) - - case IDENTtree => - setSymName() - Ident(name) - - case LITERALtree => - Literal(readConstantRef()) - - case TYPEtree => - TypeTree() - - case ANNOTATEDtree => - val annot = readTreeRef() - val arg = readTreeRef() - Annotated(annot, arg) - - case SINGLETONTYPEtree => - SingletonTypeTree(readTreeRef()) - - case SELECTFROMTYPEtree => - val qualifier = readTreeRef() - val selector = readTypeNameRef() - SelectFromTypeTree(qualifier, selector) - - case COMPOUNDTYPEtree => - CompoundTypeTree(readTemplateRef()) - - case APPLIEDTYPEtree => - val tpt = readTreeRef() - val args = until(end, readTreeRef) - AppliedTypeTree(tpt, args) - - case TYPEBOUNDStree => - val lo = readTreeRef() - val hi = readTreeRef() - TypeBoundsTree(lo, hi) - - case EXISTENTIALTYPEtree => - val tpt = readTreeRef() - val whereClauses = until(end, readTreeRef) - ExistentialTypeTree(tpt, whereClauses) + val tpe = readTypeRef() + val sym = if (isTreeSymbolPickled(tag)) readSymbolRef() else null + val result = readTree(tpe) - case _ => - noSuchTreeTag(tag, end) - } + if (sym ne null) result setSymbol sym + result setType tpe + } - if (symbol == null) t setType tpe - else t setSymbol symbol setType tpe + /* Read an abstract syntax tree */ + protected def readTree(): Tree = { + expect(TREE, "tree expected") + val end = readEnd() + readByte() match { + case EMPTYtree => EmptyTree + case tag => readNonEmptyTree(tag, end) + } } def noSuchTreeTag(tag: Int, end: Int) = -- cgit v1.2.3